{
  "openapi": "3.1.0",
  "info": {
    "title": "Tamarind Bio API",
    "version": "1.0",
    "description": "The complete Tamarind Bio public API.\n\n- **Submission, tools, results, and files** — under `/api`. Submit and manage runs of any tool in the catalog.\n- **Jobs reads** — the compatibility contract is under `/api/jobs`; the typed `/api/v1/jobs` contract is restricted to configured canary API keys until activation.\n- **Pipelines and molecules** — typed resources under `/api/pipelines` and `/api/molecules`.\n\n**Use the host that served this spec.** `servers` is set to the deployment you\nfetched from. An organisation with a dedicated deployment keeps its jobs, files and\nAPI keys in its own account, reachable only from that host — and sending to the\nshared host from such an account does NOT error: the request succeeds and the work\nlands where that user will never see it.\n\nAlmost every request authenticates with an `x-api-key` header — get one at\n`/api-docs/api-key`. **The two halves answer a bad key differently, so branch on\n\"not 2xx\" rather than on a status.** The classic submit/tools/files routes answer\n**400** (not 401), with a JSON body carrying `getApiKey`, `agentGuide` and\n`toolCatalog` so a caller can recover in place. `/api/jobs`, pipelines and molecules routes\nanswer **401** with an RFC 9457 `application/problem+json` body, which carries no\nrecovery fields — read the `Unauthorized` response of any of those operations.\n\nFour classic routes are themselves exceptions to the 400 rule. `GET /models`,\n`GET /finetuned-models` and `GET /usage-statistics` answer **401** with a bare scalar\n(`-1`, `Unauthenticated`, `Unauthorized`) and no recovery fields. `PUT /upload/{filename}`\nis not served by the API layer at all — it redirects to a CloudFront host, so an\nunauthenticated caller receives the redirect rather than any JSON body.\n\n**Exception: `GET /api/tools-catalog` (also `/tools.json`, `/tools.md`) needs NO key.**\nIt lists every publicly submittable tool `type` with its required settings, so a correct\npayload can be built before an account exists. This overview previously said every\nrequest needs a key, which sent agents away before trying the one open door."
  },
  "servers": [
    {
      "url": "https://structure-prediction-eoumat6qo-tamarind-team.vercel.app",
      "description": "Tamarind API"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/submit-job": {
      "post": {
        "summary": "Submit a single job",
        "description": "Submit a job for protein analysis using one of the available tools",
        "operationId": "submitJob",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobSubmission"
              },
              "example": {
                "jobName": "my-protein-analysis",
                "type": "alphafold",
                "settings": {
                  "sequence": "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job submitted successfully. The body is PLAIN TEXT, not JSON, and carries no job id — literally `<jobName> submitted to queue.` A generated client that calls .json() on this response throws on the HAPPY path. POLL THE NAME ECHOED IN THIS BODY, not the one you sent. `jobName` is NORMALIZED rather than validated: characters outside [A-Za-z0-9_.-] are stripped and whitespace becomes `_`, so submitting `my run!` stores `my_run` and polling `my run!` afterwards reports an unknown job. Parse the name out of this response and use that as the handle, or pre-normalize before submitting so the two cannot differ.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "my-protein-analysis submitted to queue."
                }
              }
            }
          },
          "400": {
            "description": "Bad request - invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Jobs"
        ]
      }
    },
    "/api/submit-batch": {
      "post": {
        "summary": "Submit multiple jobs as a batch",
        "description": "Submit multiple jobs in a single request for batch processing",
        "operationId": "submitBatch",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchSubmission"
              },
              "example": {
                "batchName": "my-batch-analysis",
                "type": "alphafold",
                "settings": [
                  {
                    "sequence": "QVQLQQSGAELARPGASVKMSCKASGYTFTRYTMHWVKQRPGQGLEWIGYINPSRGYTNYNQKFKDKATLTTDKSSSTAYMQLSSLTSEDSAVYYCARYYDDHYCLDYWGQGTTLTVSS"
                  },
                  {
                    "sequence": "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"
                  }
                ],
                "jobNames": [
                  "job1",
                  "job2"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch submitted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - invalid parameters"
          }
        },
        "tags": [
          "Jobs"
        ]
      }
    },
    "/api/result": {
      "post": {
        "summary": "Get job results",
        "description": "Retrieve results for a completed job",
        "operationId": "getResult",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobName"
                ],
                "properties": {
                  "jobName": {
                    "type": "string",
                    "description": "Name of the job to get results for",
                    "example": "my-protein-analysis"
                  },
                  "jobEmail": {
                    "type": "string",
                    "format": "email",
                    "description": "Email of another member of your team (optional)",
                    "example": "user@email.com"
                  },
                  "fileName": {
                    "type": "string",
                    "description": "Path to a specific file in the job results (optional)",
                    "example": "myfile.txt"
                  },
                  "pdbsOnly": {
                    "type": "boolean",
                    "description": "Return only PDB files (optional)",
                    "example": true
                  },
                  "noAsync": {
                    "type": "boolean",
                    "description": "If true, fail with 400 instead of returning a 202 \"preparing\" response when the aggregated zip is not yet built. Use this if your client cannot poll. Default: false (the server falls back to an async build on miss).",
                    "example": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job results. Returned when the aggregated zip already exists, or when the server was able to build it inline (short-ETA batches: the request is held open for up to ~290s while the batch-aggregate worker finishes, then the signed URL is returned).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string",
                  "description": "S3 presigned URL to download the job results",
                  "example": "https://s3.amazonaws.com/bucket/job-results.zip"
                }
              }
            }
          },
          "202": {
            "description": "The aggregated result zip is not yet built and its estimated build time exceeds the inline-wait budget (~290s), or the wait budget elapsed before the zip was ready. The server has kicked off (or rejoined) a batch-aggregate worker that will build it on demand and upload it to the same S3 key /result will return. Wait, then repeat the same /result call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "preparing"
                      ]
                    },
                    "jobName": {
                      "type": "string",
                      "description": "The batch parent's job name (echoed from the request)."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable polling instructions."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request"
          }
        },
        "tags": [
          "Results"
        ]
      }
    },
    "/api/upload/{filename}": {
      "put": {
        "summary": "Upload a file",
        "description": "Upload a file (PDB, sequence, etc.) for use in job submissions",
        "operationId": "uploadFile",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "filename",
            "in": "path",
            "required": true,
            "description": "Name of the file to upload",
            "schema": {
              "type": "string",
              "example": "myfile.pdb"
            }
          },
          {
            "name": "folder",
            "in": "query",
            "description": "Optional folder to upload the file to",
            "schema": {
              "type": "string",
              "example": "myFolder"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary",
                "description": "File content to upload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File uploaded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Success message",
                      "example": "File uploaded successfully"
                    },
                    "fileUrl": {
                      "type": "string",
                      "description": "URL of the uploaded file"
                    },
                    "signedUrl": {
                      "type": "string",
                      "description": "Signed URL for accessing the file"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - invalid file"
          },
          "413": {
            "description": "File too large"
          }
        },
        "tags": [
          "Files"
        ]
      }
    },
    "/api/delete-job": {
      "delete": {
        "summary": "Delete a job",
        "description": "Marks a job deleted and hides it from listings; for a batch, its subjobs too. This is a soft delete — result files in storage are not removed. An unknown job name returns 400.",
        "operationId": "deleteJob",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobName"
                ],
                "properties": {
                  "jobName": {
                    "type": "string",
                    "description": "Name of the job to delete",
                    "example": "myJobName"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Job deleted successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - job not found"
          }
        },
        "tags": [
          "Jobs"
        ]
      }
    },
    "/api/delete-file": {
      "delete": {
        "summary": "Delete a file",
        "description": "Delete a file from user account",
        "operationId": "deleteFile",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "filePath",
            "in": "query",
            "description": "Name of the file to delete",
            "schema": {
              "type": "string",
              "example": "path/to/myFileName.txt"
            }
          },
          {
            "name": "folder",
            "in": "query",
            "description": "Path to folder - deletes all files in the specified folder",
            "schema": {
              "type": "string",
              "example": "myFolder"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "File deleted successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - file not found"
          }
        },
        "tags": [
          "Files"
        ]
      }
    },
    "/api/files": {
      "get": {
        "summary": "Get user's files",
        "description": "Retrieve a list of files uploaded by the user",
        "operationId": "getFiles",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of files to return",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of files to skip",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "includeFolders",
            "in": "query",
            "description": "Include folders in the response",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "name": "folder",
            "in": "query",
            "description": "Path to folder to view files within that folder",
            "schema": {
              "type": "string",
              "example": "myFolder"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "fileId": {
                            "type": "string",
                            "description": "Unique identifier for the file"
                          },
                          "fileName": {
                            "type": "string",
                            "description": "Original filename"
                          },
                          "fileSize": {
                            "type": "integer",
                            "description": "File size in bytes"
                          },
                          "uploadTime": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the file was uploaded"
                          }
                        }
                      }
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total number of files"
                    },
                    "hasMore": {
                      "type": "boolean",
                      "description": "Whether there are more files available"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Files"
        ]
      }
    },
    "/api/tools-catalog": {
      "get": {
        "summary": "List every tool name — no API key required",
        "description": "The one endpoint on this surface that needs no credentials, so an agent can confirm a tool name is real BEFORE the user has an account. Also served at `/tools.json` (and `/tools.md`) **on this same host** — this `/api/tools-catalog` path is the same handler and is documented here so it is reachable from the spec. Follow it on the host that served this spec: the catalog names submit and schema endpoints for whichever deployment answered, so fetching it from another host hands you that host's endpoints.\n\nReturns the exact, case-sensitive `type` string to send to `/submit-job`, plus each tool's REQUIRED settings. Guessing a name is the most common way generated code fails, and an unrecognised settings key is never rejected, only flagged — so a synonym surfaces as \"missing required field\", not as an unknown-key error.\n\nDeliberately NOT the whole schema: optional parameters, defaults and descriptions need a key (`/tools/{name}/schema`). Unlike `/tools`, this is not account-scoped — it lists what a brand-new public user could submit, so feature-flagged, domain-restricted and API-gated tools are omitted.",
        "operationId": "getPublicToolCatalog",
        "security": [],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Return only this tool, so a caller that already knows the name does not have to pull the whole catalogue into context.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "description": "Return only tools carrying this intent tag (case-insensitive), e.g. `protein-ligand-docking`. The full tag list is in the `tags` field of every response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "`md` returns the catalogue as a Markdown table (`text/markdown`) instead of JSON.",
            "schema": {
              "type": "string",
              "enum": [
                "md"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The public tool catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "$comment": {
                      "type": "string",
                      "description": "How to read `requiredSettings` — that requiredness is usually conditional, which key the `tasks` predicates refer to, and what the shape-bearing fields mean. Read it before treating the list as a checklist. Declared here because a typed generator exposes only declared properties, and dropping it drops the instructions."
                    },
                    "submitEndpoint": {
                      "type": "string",
                      "description": "The absolute submit URL, on the host this response was fetched from, with its auth requirement stated. Every route lives under `/api/`; `POST /submit-job` is a 404.",
                      "example": "POST https://<the-host-that-served-this>/api/submit-job (requires x-api-key)"
                    },
                    "schemaEndpoint": {
                      "type": "string",
                      "description": "The per-tool full-schema URL. Needs a key."
                    },
                    "validateEndpoint": {
                      "type": "string",
                      "description": "Dry-run a payload without spending a job. Needs a key too — free of compute, not free of auth."
                    },
                    "agentGuide": {
                      "type": "string",
                      "description": "The complete agent guide, on the host this was fetched from."
                    },
                    "openapi": {
                      "type": "string",
                      "description": "This document, on the host this response was fetched from."
                    },
                    "mcpServer": {
                      "type": "string",
                      "description": "MCP endpoint. Not host-derived — there is no per-tenant MCP.",
                      "example": "https://mcp.tamarind.bio/mcp"
                    },
                    "filter": {
                      "type": "object",
                      "description": "Present only when `type` or `tag` narrowed the response.",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "tag": {
                          "type": "string"
                        }
                      }
                    },
                    "ignoredParamCount": {
                      "type": "integer",
                      "description": "How many query parameters this endpoint did NOT understand. Present only when at least one was ignored, so a request using only `type`, `tag` and `format` is byte-identical to before this field existed. Anything counted here was DROPPED, not applied: `?search=vina` returns the whole catalogue with `filter` absent. Treat a non-zero value as \"my filter did not happen\" and re-issue with `?type=` (exact tool name) or `?tag=` (category). Declared here for the same reason as `$comment`: a typed generator exposes only declared properties, so an undeclared warning is a warning the caller cannot see. The ignored NAMES are deliberately not echoed back — this response is read by agents, and reflecting caller-supplied text into it would make the endpoint a prompt-injection relay for anyone who can choose the URL."
                    },
                    "ignoredParamsNote": {
                      "type": "string",
                      "description": "The same fact in prose, for an agent consuming this document as text rather than as a typed object. Present exactly when `ignoredParamCount` is."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Tools in this response, after any `type`/`tag` filter"
                    },
                    "totalCount": {
                      "type": "integer",
                      "description": "Tools in the unfiltered catalogue"
                    },
                    "tags": {
                      "type": "array",
                      "description": "Every intent tag in use, for the `tag` parameter",
                      "items": {
                        "type": "string"
                      }
                    },
                    "tools": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PublicToolInfo"
                      }
                    }
                  }
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string",
                  "description": "Returned when `format=md`"
                }
              }
            }
          }
        },
        "tags": [
          "Tools"
        ]
      }
    },
    "/api/tools": {
      "get": {
        "summary": "List available tools",
        "description": "The tools this account can DISCOVER, each with its settings schema. Scoped to the caller. Fetch this rather than assuming a tool name.\n\nAbsence does not prove a tool is unsubmittable: custom tools deployed on the current platform are runnable, and their schemas are available at `/tools/{name}/schema`, but they are not listed here (see the `custom` parameter).",
        "operationId": "listTools",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "custom",
            "in": "query",
            "description": "Return your organization's custom tools instead of the built-in catalogue.\n\nLists tools from the legacy custom-tool store only. Custom tools deployed on the current platform are submittable, and their schemas are available at `/tools/{name}/schema`, but they are not returned here — if you deploy through the current platform, use the tool name you deployed rather than discovering it through this parameter.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The available tools",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ToolInfo"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key"
          }
        },
        "tags": [
          "Tools"
        ]
      }
    },
    "/api/tools/{name}/schema": {
      "get": {
        "summary": "A tool's settings as JSON Schema",
        "description": "The parameters this tool accepts, as a standard JSON Schema document, scoped to your account. Validate a `settings` object against it before submitting. Domain types JSON Schema cannot express (a PDB file, a residue selection) travel as strings and keep their original type under `x-tamarind-type`.\n\nResolved through the same classifier `POST /submit-job` uses, so the schema describes the tool version your submission will actually run. A tool you cannot see and one that does not exist both answer 404.\n\nA custom tool that is mid-deploy (status `In Queue` or `Running`) also answers 404, because `/submit-job` refuses it in that state — the schema is unavailable until its deployment finishes rather than describing a contract you cannot submit.\n\nThis is a STATIC description, for code generation, form building and offline checking. To check a specific payload's FIELDS use `POST /validate-job`, which runs the same validator `/submit-job` does and so cannot disagree with it about field values. Note it validates fields only: it does not re-check org or team tool policy, or whether a custom tool is mid-deploy, so a job can still be refused at submission for those reasons.",
        "operationId": "getToolSchema",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "toolRef",
            "in": "query",
            "description": "Describe a specific pinned build of a custom tool rather than the deployed one — the same `toolRef` accepted by `POST /submit-job`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "The tool's `name`, as returned by `GET /tools`.",
            "schema": {
              "type": "string",
              "example": "alphafold"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON Schema for the tool's settings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key. The classic surface answers 400 here rather than 401, and this endpoint follows it."
          },
          "404": {
            "description": "No such tool, or not available to this account — a tool you cannot run is reported the same way as one that does not exist."
          }
        },
        "tags": [
          "Tools"
        ]
      }
    },
    "/api/validate-job": {
      "post": {
        "summary": "Validate a job without submitting it",
        "description": "Runs the exact validation `/submit-job` runs, without submitting and at no cost. Returns 200 whether or not the payload is valid — read the `valid` field. On success `normalized` is the payload to submit, with defaults filled in.",
        "operationId": "validateJob",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "settings"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "esmfold"
                  },
                  "settings": {
                    "$ref": "#/components/schemas/JobSubmission/properties/settings"
                  },
                  "jobName": {
                    "type": "string",
                    "description": "Optional — when given, a duplicate name is reported as invalid."
                  },
                  "toolRef": {
                    "type": "string",
                    "description": "Optional. Pin validation to a specific custom-tool build (the same `toolRef` you passed to `/tools/{name}/schema`). Omit it and validation resolves the deployed version, which may declare a different set of settings than the build you fetched the schema for."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The verdict. Note that an invalid payload is also a 200.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key"
          },
          "405": {
            "description": "Method not allowed"
          }
        },
        "tags": [
          "Jobs"
        ]
      }
    },
    "/api/stop-job": {
      "post": {
        "summary": "Stop a running or queued job",
        "description": "Stops a job that is Running, In Queue, Pending or Waiting. For a batch, stops every stoppable child and the parent.",
        "operationId": "stopJob",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobName"
                ],
                "properties": {
                  "jobName": {
                    "type": "string",
                    "example": "my-protein-analysis"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stopped",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "stoppedCount": {
                      "type": "integer",
                      "description": "How many jobs were stopped, including batch children."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key, unknown job, or the job is not in a stoppable state"
          },
          "405": {
            "description": "Method not allowed"
          }
        },
        "tags": [
          "Jobs"
        ]
      }
    },
    "/api/finetuned-models": {
      "get": {
        "summary": "List your finetuned models",
        "description": "Models you own, plus those shared within your organization.",
        "operationId": "listFinetunedModels",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Filter by finetune type, e.g. plm-finetune.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The available models",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "personalModels": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FinetunedModel"
                      }
                    },
                    "organizationModels": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FinetunedModel"
                      }
                    },
                    "totalCount": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid type or limit"
          },
          "401": {
            "description": "Missing or invalid credentials"
          }
        },
        "tags": [
          "Models"
        ]
      }
    },
    "/api/usage-statistics": {
      "get": {
        "summary": "Usage statistics",
        "description": "Weighted-hours, hours, or job counts. Organization scope is the default and covers every member; if the caller is not authorized for it, the request is served at user scope instead — read `metadata.scope` to see which was applied.",
        "operationId": "getUsageStatistics",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "statistic",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hours",
                "weighted_hours",
                "jobs"
              ],
              "default": "hours"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "user",
                "organization"
              ],
              "default": "organization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage, one entry per member in scope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "email": {
                            "type": "string"
                          },
                          "total": {
                            "type": "number"
                          },
                          "tools": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    },
                    "lastUpdated": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "statistic": {
                          "type": "string"
                        },
                        "scope": {
                          "type": "string",
                          "description": "The scope actually applied, which may be narrower than requested."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid credentials"
          },
          "403": {
            "description": "Organization membership could not be verified"
          }
        },
        "tags": [
          "Usage"
        ]
      }
    },
    "/api/submit-pipeline": {
      "post": {
        "summary": "Create and run a new pipeline",
        "description": "Defines a multi-stage pipeline inline and submits it. Each stage names a task and the tools to run for it; a stage's outputs feed the next. This is the legacy pipeline API — new integrations should use the pipelines endpoints under `/api/pipelines`, which separate a reusable template from a run.",
        "operationId": "submitPipeline",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobName",
                  "stages"
                ],
                "properties": {
                  "jobName": {
                    "type": "string",
                    "description": "Name for this pipeline, unique within your account."
                  },
                  "stages": {
                    "type": "array",
                    "minItems": 1,
                    "description": "The stages to run, in order.",
                    "items": {
                      "$ref": "#/components/schemas/PipelineStage"
                    }
                  },
                  "initialInputs": {
                    "type": "array",
                    "minItems": 1,
                    "description": "Inputs fed into the first stage. Required (non-empty) whenever any first-stage setting has the value `\"pipe\"`, which marks the field that each initial input is substituted into; omitting it then is a 400 `Missing initial inputs`. Each entry is a raw sequence, or the name of a file you uploaded — `.pdb`/`.sdf` are passed through as file inputs, and a `.fa`/`.fasta` is expanded server-side into its sequences.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "projectTag": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted. Body is the plain-text confirmation `Pipeline {jobName} submitted to queue.`",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key, a missing/empty `stages`, a duplicate `jobName`, a stage with no task or tools, an unknown filter metric, or an unsupported tool."
          },
          "403": {
            "description": "A tool in the pipeline is not available to your account"
          },
          "503": {
            "description": "A tool could not be resolved (undeployed, or a transient error) — retry"
          }
        },
        "tags": [
          "Pipelines"
        ]
      }
    },
    "/api/models": {
      "get": {
        "summary": "List your deployed models",
        "description": "Custom models you have deployed, plus those shared within your organization. Deleted models are omitted.",
        "operationId": "listModels",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Return just this model instead of the full list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The deployed models — or, when `name` is given, that single model object.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "title": "Model list",
                      "type": "object",
                      "properties": {
                        "personalModels": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DeployedModel"
                          }
                        },
                        "organizationModels": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DeployedModel"
                          }
                        },
                        "allModels": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DeployedModel"
                          }
                        },
                        "totalCount": {
                          "type": "integer"
                        }
                      }
                    },
                    {
                      "title": "Single model",
                      "description": "Returned when the `name` query parameter is supplied.",
                      "$ref": "#/components/schemas/DeployedModel"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "404": {
            "description": "No model with that name"
          }
        },
        "tags": [
          "Models"
        ]
      }
    },
    "/api/deploy-model": {
      "post": {
        "summary": "Deploy a custom model",
        "description": "Deploys your own code as a tool on Tamarind. Upload the entrypoint script and any environment file first with `PUT /upload/{filename}`, then reference them by filename here. When no `environment` is given the environment is inferred, which is only supported for a `.py` entrypoint.",
        "operationId": "deployModel",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "entrypoint"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Unique model name; may not collide with a built-in tool."
                  },
                  "entrypoint": {
                    "type": "string",
                    "description": "An uploaded script path, or a command. `default` uses the image's own entrypoint."
                  },
                  "environment": {
                    "type": "string",
                    "description": "An uploaded environment file (conda, requirements, Dockerfile). Required unless the entrypoint is a `.py` script."
                  },
                  "fields": {
                    "description": "The settings your model takes, in the same shape as a tool's settings. Accepts the array or its JSON-encoded string form — deploy-model.js does `typeof fields === 'string' ? JSON.parse(fields) : fields`, so existing callers send the encoded string.",
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "description": {
                    "type": "string"
                  },
                  "tags": {
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string",
                        "description": "JSON-encoded array, accepted for backward compatibility."
                      }
                    ]
                  },
                  "gpu": {
                    "type": "boolean"
                  },
                  "outputs": {
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string"
                                },
                                "description": {
                                  "type": "string"
                                }
                              }
                            }
                          ]
                        }
                      },
                      {
                        "type": "string",
                        "description": "JSON-encoded array, accepted for backward compatibility."
                      }
                    ]
                  },
                  "outputType": {
                    "type": "string"
                  },
                  "outputDescription": {
                    "type": "string"
                  },
                  "runCommand": {
                    "type": "string"
                  },
                  "dockerImageType": {
                    "type": "string"
                  },
                  "dockerContext": {
                    "type": "string"
                  },
                  "contextZip": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deployed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeployedModel"
                }
              }
            }
          },
          "400": {
            "description": "Missing `name`/`entrypoint`, a name that already exists, a referenced file that was never uploaded, or a missing environment for a non-Python entrypoint."
          },
          "405": {
            "description": "Method not allowed"
          }
        },
        "tags": [
          "Models"
        ]
      }
    },
    "/api/run-pipeline": {
      "post": {
        "summary": "Run a saved pipeline",
        "description": "Runs a saved multi-stage pipeline by name. This is the legacy pipeline API; new integrations should use the pipelines endpoints under `/api/pipelines`.",
        "operationId": "runPipeline",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobName",
                  "pipelineName",
                  "initialInputs"
                ],
                "properties": {
                  "jobName": {
                    "type": "string",
                    "description": "Name for this pipeline execution."
                  },
                  "pipelineName": {
                    "type": "string"
                  },
                  "version": {
                    "type": "string",
                    "description": "Optional saved version; defaults to the pipeline's default."
                  },
                  "initialInputs": {
                    "type": "array",
                    "minItems": 1,
                    "description": "Uploaded .pdb filenames or raw sequences, matching the pipeline's configured input type. Must be non-empty. Basenames must be unique — child job names are derived from them.",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Pipeline \"my-pipeline\" execution \"run-01\" submitted to queue with 3 jobs."
              }
            }
          },
          "400": {
            "description": "Missing or invalid API key, or invalid inputs"
          },
          "403": {
            "description": "Denied — a tool in the pipeline is restricted for this account, or a budget cap would be exceeded."
          },
          "404": {
            "description": "Pipeline not found"
          }
        },
        "tags": [
          "Pipelines"
        ]
      }
    },
    "/api/molecules/groups": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "List Groups",
        "description": "List your molecule groups.\n\nA group is a named collection of molecules. Pass `scope=org` to include your whole organization.\n\nPaginated — follow `nextCursor` until it is null.",
        "operationId": "listGroups",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Case-insensitive substring match on the group's name.",
              "title": "Search"
            },
            "description": "Case-insensitive substring match on the group's name."
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "maxItems": 32
                },
                {
                  "type": "null"
                }
              ],
              "title": "Filter"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(mine|org)$",
              "description": "`mine` (the default) shows groups you created; `org` shows every group in your organization.",
              "default": "mine",
              "title": "Scope"
            },
            "description": "`mine` (the default) shows groups you created; `org` shows every group in your organization."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(recent|name|size)$",
              "description": "Sort by `recent` (the default, by creation date), `name`, or `size` (how many molecules the group holds). Pair with `dir`.",
              "default": "recent",
              "title": "Sort"
            },
            "description": "Sort by `recent` (the default, by creation date), `name`, or `size` (how many molecules the group holds). Pair with `dir`."
          },
          {
            "name": "dir",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(asc|desc)$",
              "description": "Sort direction, `asc` or `desc`.",
              "default": "desc",
              "title": "Dir"
            },
            "description": "Sort direction, `asc` or `desc`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of items to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of items to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal).",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicGroupPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Create Group",
        "description": "Create an empty molecule group.\n\nAdd molecules with `POST /molecules/upload` (JSON) or `POST /molecules/import-file` (a file).\n\nBind a `schemaId` to require every molecule to match that schema.",
        "operationId": "createGroup",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicGroup"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/groups/{group_id}": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Get Group",
        "description": "Fetch one group by id — its name, size, and origin.",
        "operationId": "getGroup",
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicGroup"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/schemas": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "List Schemas",
        "description": "List your schemas.\n\nPass `scope=org` to include every schema in your organization.",
        "operationId": "listSchemas",
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(mine|org)$",
              "default": "mine",
              "title": "Scope"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of items to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of items to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal).",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSchemaPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Create Schema",
        "description": "Define a reusable set of typed fields you can bind to a group.\n\nScalar fields (`string`, `integer`, `float`, `boolean`, `category`) constrain a molecule's metadata.\n\nA `chain` field describes a required chain, named by its `name`.",
        "operationId": "createSchema",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateSchemaRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSchema"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/schemas/{schema_id}": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Get Schema",
        "description": "Fetch one schema by id.",
        "operationId": "getSchema",
        "parameters": [
          {
            "name": "schema_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Schema Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSchema"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Update Schema",
        "description": "Update a schema's name and/or fields.\n\nSending `fields` replaces the whole list.\n\nMolecules already published to bound groups are left as they are. Imports that have not\npublished yet are validated against the current schema at publication.",
        "operationId": "updateSchema",
        "parameters": [
          {
            "name": "schema_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Schema Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicUpdateSchemaRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSchema"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/remove": {
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Remove Molecules",
        "description": "Remove molecules from a group.\n\nThis detaches group membership; it does not delete the molecule, which stays in any other groups with its scores and files intact. To delete a molecule everywhere, use `DELETE /molecules/{moleculeId}`.\n\nIdempotent — ids not in the group are ignored, and `removedIds` lists what was detached.",
        "operationId": "removeMolecules",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicRemoveMoleculesFromGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRemoveMoleculesResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/upload": {
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Upload Molecules",
        "description": "Queue molecules for JSON upload ingestion.\n\nReturns HTTP 202 with the exact content-addressed molecule ids and an import id.\nPoll `GET /molecules/imports/{importId}` until the import reaches `ingested`,\n`failed`, or `cancelled`; the ids become readable only after ingestion succeeds.",
        "operationId": "uploadMolecules",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicUploadRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUploadResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/import-file": {
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Start a file import",
        "description": "Import molecules from a file. Step 1 of 3.\n\nThen `PUT` the bytes to `uploadUrl`, and `POST\n/molecules/imports/{importId}/commit` to enqueue ingestion.\n\nFor a CSV, describe your chain columns with `chainMapping` (keyed by chain id);\n`columnMapping` handles the scalar columns only. For `pdb`/`sdf`/`fasta`/`zip`\nthe chains are read from the file.",
        "operationId": "importFile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicFileImportRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicFileImportStart"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/imports/{import_id}": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Check import status",
        "description": "Poll an import's progress after upload or commit.\n\nStatus moves `created` → `uploaded` → `queued` → `ingested` (or `failed` / `cancelled`).\n\nIt reflects this import specifically, not the target group's overall state.",
        "operationId": "getImport",
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Import Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicImportStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Cancel or delete an import",
        "description": "Cancel an unclaimed import and clean its source objects.",
        "operationId": "deleteImport",
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Import Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/imports/{import_id}/commit": {
      "post": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Commit an import",
        "description": "Step 3 of 3: enqueue ingestion for the uploaded file.\n\n- Returns `status: \"queued\"` immediately by default — poll `GET /molecules/imports/{importId}`.",
        "operationId": "commitImport",
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Import Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PublicCommitRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCommitQueued"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "List Molecules",
        "description": "List your molecules, most recently created first.\n\nEach molecule includes its chains, scores, metadata, and files inline. Pass `scope=org` to list across your whole organization.\n\nSearch by `group`, `jobId`/`jobName`, tool, name, or protein-sequence / SMILES subsequence. Filter or sort by tool scores (e.g. `alphafold.ptm`).\n\nPaginated — follow `nextCursor` until it is null.",
        "operationId": "listMolecules",
        "parameters": [
          {
            "name": "group",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Limit to one group (by id). A group that isn't yours returns an empty page.",
              "title": "Group"
            },
            "description": "Limit to one group (by id). A group that isn't yours returns an empty page."
          },
          {
            "name": "jobId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Limit to one job's molecules (produced or consumed). Pass a batch id, not a child job id.",
              "title": "Jobid"
            },
            "description": "Limit to one job's molecules (produced or consumed). Pass a batch id, not a child job id."
          },
          {
            "name": "jobName",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Same as `jobId`, by job/batch name. Names aren't unique — all visible matches are included.",
              "title": "Jobname"
            },
            "description": "Same as `jobId`, by job/batch name. Names aren't unique — all visible matches are included."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MoleculeType"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Limit by molecule kind (e.g. protein, small_molecule, nucleic_acid).",
              "title": "Type"
            },
            "description": "Limit by molecule kind (e.g. protein, small_molecule, nucleic_acid)."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 10000
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search term. `mode=default` (or `name`) matches molecule names, metadata keys, and score metrics; ungrouped searches require at least 3 characters. `mode=sequence` matches an amino-acid sequence of at least 3 characters.",
              "title": "Search"
            },
            "description": "Search term. `mode=default` (or `name`) matches molecule names, metadata keys, and score metrics; ungrouped searches require at least 3 characters. `mode=sequence` matches an amino-acid sequence of at least 3 characters."
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(default|name|sequence)$",
              "description": "How `search` is read. `default` (alias `name`) matches names, metadata keys, and score metrics. With no `sortBy`, `filter`, or `sequence`, it is a complete chunked scan: follow `nextCursor` until null, including through empty or short pages. Adding any of those options uses capped ranked pagination, so a null cursor completes that page, not every possible name match. `sequence` is a complete chunked scan over amino-acid chains. Check the echoed `mode`.",
              "default": "default",
              "title": "Mode"
            },
            "description": "How `search` is read. `default` (alias `name`) matches names, metadata keys, and score metrics. With no `sortBy`, `filter`, or `sequence`, it is a complete chunked scan: follow `nextCursor` until null, including through empty or short pages. Adding any of those options uses capped ranked pagination, so a null cursor completes that page, not every possible name match. `sequence` is a complete chunked scan over amino-acid chains. Check the echoed `mode`."
          },
          {
            "name": "sequenceMatch",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(subsequence|exact)$",
              "description": "With `mode=sequence`, how to match the term: `subsequence` (default) — chains contain it; `exact` — a chain equals it. Rejected in name mode.",
              "default": "subsequence",
              "title": "Sequencematch"
            },
            "description": "With `mode=sequence`, how to match the term: `subsequence` (default) — chains contain it; `exact` — a chain equals it. Rejected in name mode."
          },
          {
            "name": "examplesPerGroup",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 25,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "description": "Cap how many molecules each group contributes to a page (requires `sortBy=groupName`). Not allowed with `mode=sequence`.",
              "title": "Examplespergroup"
            },
            "description": "Cap how many molecules each group contributes to a page (requires `sortBy=groupName`). Not allowed with `mode=sequence`."
          },
          {
            "name": "sequence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Match molecules containing this amino-acid subsequence in any chain (case-insensitive, at least 3 characters).",
              "title": "Sequence"
            },
            "description": "Match molecules containing this amino-acid subsequence in any chain (case-insensitive, at least 3 characters)."
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "maxItems": 32
                },
                {
                  "type": "null"
                }
              ],
              "description": "Repeatable `field:operator:value` predicate, AND-ed, on a metadata field or tool score (`tool.metric`). Operators: `gt`, `gte`, `lt`, `lte`, `eq`, `neq`, `exists` (written `field:exists`, no value — metadata fields only). Append `:jobId` to pin a tool score to one job.",
              "title": "Filter"
            },
            "description": "Repeatable `field:operator:value` predicate, AND-ed, on a metadata field or tool score (`tool.metric`). Operators: `gt`, `gte`, `lt`, `lte`, `eq`, `neq`, `exists` (written `field:exists`, no value — metadata fields only). Append `:jobId` to pin a tool score to one job."
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(mine|org)$",
              "description": "`mine` (the default) shows molecules in groups you created; `org` shows everything across your organization.",
              "default": "mine",
              "title": "Scope"
            },
            "description": "`mine` (the default) shows molecules in groups you created; `org` shows everything across your organization."
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200,
              "description": "Sort by a built-in column (`id`, `added`, `type`, `groupName`) or a metadata field / tool score (`tool.metric`, on the tool's best run). `groupName` keeps a group's rows together — pair with `examplesPerGroup`.",
              "default": "added",
              "title": "Sortby"
            },
            "description": "Sort by a built-in column (`id`, `added`, `type`, `groupName`) or a metadata field / tool score (`tool.metric`, on the tool's best run). `groupName` keeps a group's rows together — pair with `examplesPerGroup`."
          },
          {
            "name": "dir",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(asc|desc)$",
              "description": "Sort direction, `asc` or `desc`.",
              "default": "desc",
              "title": "Dir"
            },
            "description": "Sort direction, `asc` or `desc`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of items to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of items to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal).",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMoleculePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/{molecule_id}/metadata": {
      "patch": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Update Molecule Metadata",
        "description": "Update a molecule. All fields are optional and applied together; `null` clears a field.\n\nMerge your own annotations with `properties` (tool scores aren't editable here). Set the derived-from molecule with `source`, this group's primary structure file with `fileId`, and the per-group display name with `name`.\n\nA `name` already used in the group returns `409`.",
        "operationId": "updateMoleculeMetadata",
        "parameters": [
          {
            "name": "molecule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Molecule Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicUpdateMetadataRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMolecule"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/{molecule_id}/groups": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "List Molecule Groups",
        "description": "List every group a molecule belongs to.\n\nUse this when `GET /molecules/{moleculeId}` marks `groups` as truncated. Only your own groups are listed.\n\nPaginated — follow `nextCursor` until it is null.",
        "operationId": "listMoleculeGroups",
        "parameters": [
          {
            "name": "molecule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Molecule Id"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of items to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of items to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal).",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`. Omit for the first page; follow `nextCursor` until null (an empty `items` page while `nextCursor` is set is normal)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicGroupPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/molecules/{molecule_id}": {
      "get": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Get Molecule",
        "description": "Get one molecule — its chains, scores, files, provenance, and groups, all inline.\n\nAddressed by its id; no group needed.\n\nChain labels are per-group, so pass `groupId` to choose which group's labels you get, else the most recent group wins.",
        "operationId": "getMolecule",
        "parameters": [
          {
            "name": "molecule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Molecule Id"
            }
          },
          {
            "name": "groupId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "title": "Groupid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMolecule"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "molecules-public"
        ],
        "summary": "Delete Molecule",
        "description": "Permanently delete a molecule. Admin only.\n\nRemoves the molecule and all its group memberships, scores, and file links across the organization. To remove it from one group instead, use `POST /molecules/remove`.\n\nIdempotent — an unknown id returns `deleted: false`.",
        "operationId": "deleteMolecule",
        "parameters": [
          {
            "name": "molecule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Molecule Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDeleteMoleculeResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/pipelines/templates": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Create a pipeline template",
        "description": "Create a pipeline template from a `pipeline` graph of inputs, tools, and filters.\n\n- The graph is validated on create\n- This first save becomes the template's first version; every later save adds a new immutable version",
        "operationId": "createTemplate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTemplate"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      },
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "List pipeline templates",
        "description": "List pipeline templates in your account or organization.",
        "operationId": "listTemplates",
        "parameters": [
          {
            "name": "isPublished",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter to published (`true`) or unpublished (`false`) templates.",
              "title": "Ispublished"
            },
            "description": "Filter to published (`true`) or unpublished (`false`) templates."
          },
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "mine",
                    "org"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Whose templates to list: `mine` (the default) or `org` for your whole organization.",
              "title": "Owner"
            },
            "description": "Whose templates to list: `mine` (the default) or `org` for your whole organization."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search pipelines by name.",
              "title": "Search"
            },
            "description": "Search pipelines by name."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of templates to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of templates to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`.",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTemplatePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/templates/{template_id}": {
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Get a pipeline template",
        "description": "Retrieve a template by id to view its nodes and required inputs.",
        "operationId": "getTemplate",
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            }
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1
                },
                {
                  "type": "null"
                }
              ],
              "description": "A specific version to view (a `vN` handle); omit for the current version.",
              "title": "Version"
            },
            "description": "A specific version to view (a `vN` handle); omit for the current version."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTemplate"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      },
      "delete": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Delete a pipeline template",
        "description": "Delete a template and all its versions.\n\n- Existing runs keep their own copies and are unaffected",
        "operationId": "deleteTemplate",
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/templates/{template_id}/publish": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Publish a template version",
        "description": "Publish a version of your pipeline template to your organization.\n\nOthers in your organization may only run pipelines published to the organization\n\nOnly one version can be published at a time",
        "operationId": "publishTemplate",
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicPublishRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPublishResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/templates/{template_id}/duplicate": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Duplicate a pipeline template",
        "description": "Create a copy of a version of your existing pipeline (latest by default).",
        "operationId": "duplicateTemplate",
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PublicDuplicateTemplateRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTemplate"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/templates/{template_id}/validate": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Validate a template",
        "description": "Validate the settings and inputs of a template without creating or executing it.\n\nValidates your pipeline to ensure compatible connections, required tool settings, and valid graph structure.",
        "operationId": "validateTemplate",
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PublicValidateTemplateRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicValidateResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/submit": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Submit a pipeline run",
        "description": "Submit a pipeline run from an existing template, or from a new pipeline graph.\n\nProvide a `bindings` map, which defines the molecules/files you want to use for each input node in your pipeline. If your input contains chains, define the mapping of chain IDs between your molecule and the pipeline's reference/default (if running against an existing template).\n\nBindings may be defined as an array of sequences, smiles, or sdf/pdb files (uploaded using the /upload endpoint), or an existing molecule group id (created using /molecules/groups below).\n\nIf applicable, you may use the `residuesByChain` setting to define selected residues across tools which require hotspots / designed residues to be specified.\n\nChoose from your pipelines or example templates to view example scripts.",
        "operationId": "submitPipeline",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 255
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicSubmitPipelineRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/validate": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Validate a pipeline run",
        "description": "Validate the settings and inputs of a run without creating or executing it. Uses the same settings as `/submit`.\n\nValidates your pipeline to ensure compatible connections, required tool settings, and valid graph structure.",
        "operationId": "validateRun",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicSubmitPipelineRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicValidateResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/runs": {
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "List pipeline runs",
        "description": "List pipeline runs in your organization.",
        "operationId": "listRuns",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/RunStatus"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by run status.",
              "title": "Status"
            },
            "description": "Filter by run status."
          },
          {
            "name": "templateId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter to runs of one pipeline (by template id).",
              "title": "Templateid"
            },
            "description": "Filter to runs of one pipeline (by template id)."
          },
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "mine",
                    "org"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Whose runs to list: `mine` (the default) or `org` for your whole organization.",
              "title": "Owner"
            },
            "description": "Whose runs to list: `mine` (the default) or `org` for your whole organization."
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "test",
                    "production"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by run source: `test` or `production`.",
              "title": "Source"
            },
            "description": "Filter by run source: `test` or `production`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of runs to return in one page.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of runs to return in one page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`.",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRunPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/runs/results": {
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Download a pipeline run's results",
        "description": "Download full raw results for pipeline by its job name",
        "operationId": "getRunResults",
        "parameters": [
          {
            "name": "jobName",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "The run's job name.",
              "title": "Jobname"
            },
            "description": "The run's job name."
          },
          {
            "name": "user",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 320
                },
                {
                  "type": "null"
                }
              ],
              "description": "The run owner's email — needed only to disambiguate a job name shared across accounts.",
              "title": "User"
            },
            "description": "The run owner's email — needed only to disambiguate a job name shared across accounts."
          },
          {
            "name": "node",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1
                },
                {
                  "type": "null"
                }
              ],
              "description": "Scope the ZIP to one step — a `steps[].id` from `GET /runs/{id}`.",
              "title": "Node"
            },
            "description": "Scope the ZIP to one step — a `steps[].id` from `GET /runs/{id}`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRunResults"
                }
              }
            }
          },
          "202": {
            "description": "The archive is still being built — GET again to keep waiting."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/runs/{run_id}": {
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Get a pipeline run",
        "description": "Query a run for its status overall and per-node, along with output results.",
        "operationId": "getRun",
        "parameters": [
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Run Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/runs/{run_id}/steps/{step_id}/molecules": {
      "get": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "List the molecules a step produced",
        "description": "The molecules one step produced, with their scores.\n\nRead a step's results through this, not through `PublicStep.outputGroup`. `outputGroup` is the group a step MINTED, and two common kinds of step mint none: a step that enriches its inputs in place (scoring, structure prediction) leaves its molecules in the group they came from, and a filter step's survivors exist only as step outputs. For both, `outputGroup` is correctly `null` — reading results by group reports 'produced nothing' for exactly the steps whose output you asked for. This endpoint answers for every kind of step.\n\n`step_id` is the `id` of an entry in the run's `steps`.",
        "operationId": "listStepMolecules",
        "parameters": [
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Run Id"
            }
          },
          {
            "name": "step_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Step Id"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Molecules per page.",
              "default": 25,
              "title": "Limit"
            },
            "description": "Molecules per page."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "description": "Pagination token from the previous response's `nextCursor`.",
              "title": "Cursor"
            },
            "description": "Pagination token from the previous response's `nextCursor`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicStepMoleculePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/pipelines/runs/{run_id}/stop": {
      "post": {
        "tags": [
          "pipelines-public"
        ],
        "summary": "Stop a pipeline run",
        "description": "Stop a pipeline run.\n\nAny jobs which have not yet completed are stopped, including running jobs.\nOutputs of any completed jobs are saved and may be viewed.",
        "operationId": "stopRun",
        "parameters": [
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Run Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Pipelines"
      }
    },
    "/api/model-router": {
      "post": {
        "tags": [
          "model-router-public"
        ],
        "summary": "Recommend a tool for a task",
        "description": "Recommend which structure-prediction tool to run, in ranked order.\n\nDescribe the task in your own words. `tools` comes back ranked, best first — run the first\none. Send your sequences under `inputs` when you have them and the answer gets more\nspecific; a sequence pasted into the prompt itself is found and used as well, so a plain\nprompt still gets benchmark matching.\n\n`abstain` is the other normal response: no tool could be justified, and `uncertainties`\nsays what was missing — usually that the request did not say enough. Say more in the\nprompt and call again.\n\nNote that `evidenceStrength` says how much is known about a tool, not how good it is, so\ndo not rank on it. A call takes about 15 to 25 seconds.",
        "operationId": "recommendTools",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicToolRecommendationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicToolRecommendation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Model router"
      }
    },
    "/api/custom-tools": {
      "get": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "List Tools",
        "description": "List custom tools visible to the caller.",
        "operationId": "listCustomTools",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomToolPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      },
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Create Tool",
        "description": "Create a custom tool. Upload source and deploy it with separate requests.",
        "operationId": "createCustomTool",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateCustomToolRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomTool"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}": {
      "get": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Get Tool",
        "description": "Get configuration and source readiness for a custom tool.",
        "operationId": "getCustomTool",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomTool"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      },
      "patch": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Update Tool",
        "description": "Update custom-tool metadata and compute resources.",
        "operationId": "updateCustomTool",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicUpdateCustomToolRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomTool"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/uploads": {
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Create Upload",
        "description": "Create a presigned source-archive upload.",
        "operationId": "createCustomToolUpload",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUploadSession"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/uploads/{upload_id}/finalize": {
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Finalize Upload",
        "description": "Start extraction. Poll until the tool's source hash matches the uploaded archive.",
        "operationId": "finalizeCustomToolUpload",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "upload_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200,
              "pattern": "^[A-Za-z0-9-]+$",
              "title": "Upload Id"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUploadFinalized"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/deploy": {
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Deploy Tool",
        "description": "Deploy the current source using the existing custom-tool build lifecycle.",
        "operationId": "deployCustomTool",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicDeployRequest",
                "default": {}
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDeployResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/versions": {
      "get": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "List Tool Versions",
        "description": "List versions newest first.",
        "operationId": "listCustomToolVersions",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 50,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicVersionPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/versions/{version_name}": {
      "get": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Get Tool Version",
        "description": "Get one version by its numbered name.",
        "operationId": "getCustomToolVersion",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "version_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "pattern": "^v[1-9][0-9]*$",
              "title": "Version Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicVersion"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/versions/{version_name}/logs": {
      "get": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Get Version Logs",
        "description": "Poll build status and logs for a version.",
        "operationId": "listCustomToolBuildLogs",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "version_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "pattern": "^v[1-9][0-9]*$",
              "title": "Version Name"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 4096
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBuildLogPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/versions/{version_name}/cancel": {
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Cancel Version",
        "description": "Cancel a running version build.",
        "operationId": "cancelCustomToolBuild",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "version_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "pattern": "^v[1-9][0-9]*$",
              "title": "Version Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/custom-tools/{name}/versions/{version_name}/publish": {
      "post": {
        "tags": [
          "custom-tools-public"
        ],
        "summary": "Publish Version",
        "description": "Publish a completed version as the tool's current runtime version.",
        "operationId": "publishCustomToolVersion",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 50,
              "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
              "title": "Name"
            }
          },
          {
            "name": "version_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "pattern": "^v[1-9][0-9]*$",
              "title": "Version Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomTool"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Custom Tools"
      }
    },
    "/api/jobs": {
      "get": {
        "tags": [
          "jobs-compatibility"
        ],
        "summary": "List jobs (compatibility)",
        "description": "Compatibility contract for existing `/api/jobs` clients, including exact-name, batch-child, organization, member, subjob, batch-only, and legacy pagination modes. New integrations should use the typed `/api/v1/jobs` contract.",
        "operationId": "listCompatibleJobs",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 1000,
              "minimum": 1,
              "default": 1000,
              "title": "Limit"
            }
          },
          {
            "name": "startKey",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 16384
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startkey"
            }
          },
          {
            "name": "jobName",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "title": "Jobname"
            }
          },
          {
            "name": "includeSequences",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Includesequences"
            }
          },
          {
            "name": "includeSubjobs",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Includesubjobs"
            }
          },
          {
            "name": "organization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Organization"
            }
          },
          {
            "name": "batchOnly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Batchonly"
            }
          },
          {
            "name": "batch",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "title": "Batch"
            }
          },
          {
            "name": "jobEmail",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 320
                },
                {
                  "type": "null"
                }
              ],
              "title": "Jobemail"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/LegacyJobPage"
                    },
                    {
                      "$ref": "#/components/schemas/LegacySingleJob"
                    }
                  ],
                  "title": "Response Listcompatiblejobs"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/v1/jobs": {
      "get": {
        "tags": [
          "jobs-public"
        ],
        "summary": "List jobs",
        "description": "List standalone jobs and batch parents visible to the caller. During dark launch this operation is available only to configured canary API-key principals.",
        "operationId": "listJobs",
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "const": "mine",
              "type": "string",
              "description": "List jobs visible to your API key. `mine` is the only supported value.",
              "default": "mine",
              "title": "Scope"
            },
            "description": "List jobs visible to your API key. `mine` is the only supported value."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicJobStatus"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Return jobs in these states. Repeat `status` to match more than one state.",
              "title": "Status"
            },
            "description": "Return jobs in these states. Repeat `status` to match more than one state."
          },
          {
            "name": "tool",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ],
              "description": "Return jobs submitted with this exact tool type, such as `alphafold`.",
              "title": "Tool"
            },
            "description": "Return jobs submitted with this exact tool type, such as `alphafold`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "description": "Maximum number of jobs to return. A filtered page may contain fewer items.",
              "default": 50,
              "title": "Limit"
            },
            "description": "Maximum number of jobs to return. A filtered page may contain fewer items."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 16384
                },
                {
                  "type": "null"
                }
              ],
              "description": "The `nextCursor` from the previous response. Omit for the first page.",
              "title": "Cursor"
            },
            "description": "The `nextCursor` from the previous response. Omit for the first page."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicJobPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Jobs"
      }
    },
    "/api/v1/jobs/{job_id}": {
      "get": {
        "tags": [
          "jobs-public"
        ],
        "summary": "Get job details",
        "description": "Get one job by its opaque id. During dark launch this operation is available only to configured canary API-key principals.",
        "operationId": "getJob",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4104,
              "description": "The opaque `id` returned by `GET /v1/jobs`.",
              "title": "Job Id"
            },
            "description": "The opaque `id` returned by `GET /v1/jobs`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicJobDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationProblem"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-doc-group": "Jobs"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your Tamarind API key. Create one at https://app.tamarind.bio/api-docs/api-key."
      }
    },
    "schemas": {
      "DiagnosticCode": {
        "type": "string",
        "enum": [
          "parse-error",
          "shape-violation",
          "structural-limit",
          "cycle",
          "dangling-ref",
          "unsupported-schema-version",
          "tool-unknown",
          "setting-invalid",
          "param-out-of-range",
          "required-field-unset",
          "input-unbound",
          "input-missing-reference",
          "chain-incompatible",
          "chain-unsatisfied",
          "molecule-class-incompatible",
          "binding-invalid",
          "budget-exceeded",
          "tool-not-licensed",
          "runtime-unresolved",
          "unknown"
        ],
        "title": "DiagnosticCode",
        "description": "The PUBLIC validation-diagnostic vocabulary — the stable value set a caller may switch on.\n\nThis is a CURATED contract, not a passthrough of the internal code set: the mapper\n(`_map/pipelines._diagnostic`) translates each internal code to one of these, and an internal\ncode with no public mapping becomes `unknown` (never a raw internal string). So a new INTERNAL\ndiagnostic code cannot silently enter the public contract — adding a public code is a deliberate,\nv1-frozen change. Keep in sync with the mapper's translation table."
      },
      "Flow": {
        "type": "string",
        "enum": [
          "molecule",
          "file"
        ],
        "title": "Flow"
      },
      "LegacyJobPage": {
        "properties": {
          "jobs": {
            "items": {
              "$ref": "#/components/schemas/LegacyJobSummary"
            },
            "type": "array",
            "title": "Jobs"
          },
          "startKey": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Startkey"
          },
          "statuses": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "Statuses"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "jobs",
          "statuses"
        ],
        "title": "LegacyJobPage"
      },
      "LegacyJobStatus": {
        "type": "string",
        "enum": [
          "In Queue",
          "Running",
          "Complete",
          "Failed",
          "Stopped"
        ],
        "title": "LegacyJobStatus"
      },
      "LegacyJobSummary": {
        "properties": {
          "JobName": {
            "type": "string",
            "title": "Jobname"
          },
          "JobStatus": {
            "$ref": "#/components/schemas/LegacyJobStatus"
          },
          "Created": {
            "type": "string",
            "title": "Created"
          },
          "Type": {
            "type": "string",
            "title": "Type"
          },
          "Settings": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings"
          },
          "Score": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Score"
          },
          "Started": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started"
          },
          "Completed": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completed"
          },
          "Batch": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Batch"
          },
          "TamarindSchemaVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tamarindschemaversion"
          },
          "WeightedHours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Weightedhours"
          },
          "User": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "User"
          },
          "batchStatus": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Running",
                  "Aggregating",
                  "Complete",
                  "Stopped",
                  "AggregationFailed"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Batchstatus"
          },
          "AggregationError": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Aggregationerror"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "JobName",
          "JobStatus",
          "Created",
          "Type"
        ],
        "title": "LegacyJobSummary",
        "description": "Fields published by the old handler after its explicit keep-list and enrichments."
      },
      "LegacySingleJob": {
        "properties": {
          "JobName": {
            "type": "string",
            "title": "Jobname"
          },
          "JobStatus": {
            "$ref": "#/components/schemas/LegacyJobStatus"
          },
          "Created": {
            "type": "string",
            "title": "Created"
          },
          "Type": {
            "type": "string",
            "title": "Type"
          },
          "Settings": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings"
          },
          "Score": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Score"
          },
          "Started": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started"
          },
          "Completed": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completed"
          },
          "Batch": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Batch"
          },
          "TamarindSchemaVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tamarindschemaversion"
          },
          "WeightedHours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Weightedhours"
          },
          "User": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "User"
          },
          "batchStatus": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Running",
                  "Aggregating",
                  "Complete",
                  "Stopped",
                  "AggregationFailed"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Batchstatus"
          },
          "AggregationError": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Aggregationerror"
          },
          "statuses": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "Statuses"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "JobName",
          "JobStatus",
          "Created",
          "Type",
          "statuses"
        ],
        "title": "LegacySingleJob"
      },
      "MoleculeChainInfo": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags"
          }
        },
        "type": "object",
        "required": [
          "type",
          "tags"
        ],
        "title": "MoleculeChainInfo",
        "description": "Type + role tags of one chain in a molecule's `entity`, keyed by the same\nchain id — so a reader tells a protein sequence from a SMILES, and sees\nheavy/light/lead roles, without loading the group's schema."
      },
      "MoleculeClass": {
        "type": "string",
        "enum": [
          "protein",
          "small_molecule",
          "nucleic_acid"
        ],
        "title": "MoleculeClass"
      },
      "MoleculeFileEntry": {
        "properties": {
          "fileName": {
            "type": "string",
            "title": "Filename"
          },
          "fileType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Filetype"
          },
          "downloadUrl": {
            "type": "string",
            "title": "Downloadurl"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "fileName",
          "fileType",
          "downloadUrl",
          "createdAt"
        ],
        "title": "MoleculeFileEntry",
        "description": "One structure file on a molecule. Appears in the `files` map, whose KEY is\nthe producer (a job/tool name, or `user` for uploads)."
      },
      "MoleculeType": {
        "type": "string",
        "enum": [
          "protein",
          "antibody",
          "peptide",
          "enzyme",
          "small_molecule",
          "nucleic_acid",
          "small_molecule_binding_protein"
        ],
        "title": "MoleculeType",
        "description": "The spec's `MoleculeType` — the kind of a molecule, and of the molecules a\ngroup holds.\n\nValue-identical to the internal `Modality` (the user-picked upload modality),\nwhich is the superset enum `complexes.type` is written from. Declared\nseparately because it is a PUBLISHED contract: `Modality` is free to grow a\nvalue for an internal picker without that value silently becoming part of the\npublic API. `public_types_match_modality` pins them equal today."
      },
      "PipelineIR": {
        "properties": {},
        "additionalProperties": true,
        "type": "object",
        "title": "PipelineIR",
        "description": "A pipeline IR document. Full schema (typed, versioned): https://tamarind.bio/schemas/pipeline-v1.json"
      },
      "PublicBinding": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/PublicMoleculeBinding"
          },
          {
            "$ref": "#/components/schemas/PublicFileBinding"
          }
        ],
        "title": "PublicBinding"
      },
      "PublicBuildEvent": {
        "properties": {
          "message": {
            "type": "string",
            "title": "Message"
          },
          "timestamp": {
            "type": "integer",
            "title": "Timestamp"
          }
        },
        "type": "object",
        "required": [
          "message",
          "timestamp"
        ],
        "title": "PublicBuildEvent"
      },
      "PublicBuildLogPage": {
        "properties": {
          "buildStatus": {
            "type": "string",
            "title": "Buildstatus"
          },
          "logs": {
            "items": {
              "$ref": "#/components/schemas/PublicBuildEvent"
            },
            "type": "array",
            "title": "Logs"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          },
          "errorMessage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Errormessage"
          }
        },
        "type": "object",
        "required": [
          "buildStatus",
          "logs"
        ],
        "title": "PublicBuildLogPage"
      },
      "PublicCcdInput": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "ccd",
            "title": "Kind",
            "description": "A ligand identified by a PDB CCD code."
          },
          "parameter": {
            "type": "string",
            "title": "Parameter",
            "description": "The tool setting that received this input."
          },
          "ccdCode": {
            "type": "string",
            "title": "Ccdcode",
            "description": "The submitted PDB Chemical Component Dictionary code."
          },
          "source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicLiteralInputSource"
              },
              {
                "$ref": "#/components/schemas/PublicMoleculeInputSource"
              }
            ],
            "title": "Source",
            "description": "Where this input value came from.",
            "discriminator": {
              "propertyName": "kind",
              "mapping": {
                "literal": "#/components/schemas/PublicLiteralInputSource",
                "molecule": "#/components/schemas/PublicMoleculeInputSource"
              }
            }
          }
        },
        "type": "object",
        "required": [
          "kind",
          "parameter",
          "ccdCode",
          "source"
        ],
        "title": "PublicCcdInput"
      },
      "PublicChainMappingEntry": {
        "properties": {
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicChainType"
              },
              {
                "type": "null"
              }
            ]
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/PublicChainTag"
                },
                "type": "array",
                "maxItems": 3
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags",
            "description": "Roles for this chain. A chain is `heavy` OR `light`, never both (storage keeps one subtype); `lead` is compatible with either. Omit to inherit the schema's tag."
          },
          "csvColumn": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Csvcolumn"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicChainMappingEntry",
        "description": "The spec's `ChainMappingEntry` — how ONE chain is defined for ingestion,\nkeyed by chain id.\n\nThis is what REPLACED the old fixed CSV role vocabulary\n(`heavy_chain`/`light_chain`/`sequence`/...), which could only describe\nantibody-shaped data and could not name a chain id at all (design notes §1)."
      },
      "PublicChainTag": {
        "type": "string",
        "enum": [
          "heavy",
          "light",
          "lead"
        ],
        "title": "PublicChainTag",
        "description": "The spec's `ChainTag` — the functional role of one chain."
      },
      "PublicChainType": {
        "type": "string",
        "enum": [
          "protein",
          "small_molecule"
        ],
        "title": "PublicChainType",
        "description": "The spec's `ChainType` — the molecular kind of one chain."
      },
      "PublicCommitQueued": {
        "properties": {
          "importId": {
            "type": "string",
            "title": "Importid"
          },
          "status": {
            "type": "string",
            "const": "queued",
            "title": "Status",
            "default": "queued"
          },
          "groupName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupname"
          }
        },
        "type": "object",
        "required": [
          "importId",
          "groupName"
        ],
        "title": "PublicCommitQueued",
        "description": "Returned after the import is queued."
      },
      "PublicCommitRequest": {
        "properties": {
          "columnMapping": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Columnmapping"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicCommitRequest",
        "description": "The spec's `CommitRequest` — optional overrides applied at commit time."
      },
      "PublicCreateCustomToolRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 50,
            "minLength": 3,
            "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$",
            "title": "Name"
          },
          "displayName": {
            "type": "string",
            "maxLength": 200,
            "title": "Displayname",
            "default": ""
          },
          "description": {
            "type": "string",
            "maxLength": 2000,
            "title": "Description",
            "default": ""
          },
          "gpuType": {
            "type": "string",
            "enum": [
              "None",
              "T4",
              "L4",
              "L40S",
              "A10",
              "A100"
            ],
            "title": "Gputype",
            "default": "None"
          },
          "memory": {
            "type": "string",
            "enum": [
              "8Gi",
              "12Gi",
              "24Gi",
              "32Gi",
              "48Gi",
              "64Gi",
              "90Gi",
              "96Gi",
              "180Gi"
            ],
            "title": "Memory",
            "default": "8Gi"
          },
          "cpu": {
            "type": "integer",
            "maximum": 8,
            "minimum": 1,
            "title": "Cpu",
            "default": 1
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name"
        ],
        "title": "PublicCreateCustomToolRequest"
      },
      "PublicCreateGroupRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name"
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MoleculeType"
              },
              {
                "type": "null"
              }
            ]
          },
          "schemaId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Schemaid"
          },
          "orgId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Orgid"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 64,
            "title": "Tags"
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name"
        ],
        "title": "PublicCreateGroupRequest",
        "description": "The spec's `CreateGroupRequest`.\n\nInline group creation was dropped from upload/import, so this is now the ONLY\nway a group comes into existence on the public surface."
      },
      "PublicCreateSchemaRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name"
          },
          "fields": {
            "items": {
              "$ref": "#/components/schemas/PublicSchemaField"
            },
            "type": "array",
            "maxItems": 200,
            "minItems": 1,
            "title": "Fields"
          },
          "orgId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Orgid"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name",
          "fields"
        ],
        "title": "PublicCreateSchemaRequest"
      },
      "PublicCreateTemplateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "pipeline": {
            "$ref": "#/components/schemas/PipelineIR",
            "description": "The pipeline IR. Every molecule `user_input` node must name a reference group in `metadata.defaultGroup` (the molecules the template is authored against — a run binds its own group at submit); a molecule input without one is rejected 422 `input-missing-reference`. File inputs are exempt."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name",
          "pipeline"
        ],
        "title": "PublicCreateTemplateRequest",
        "example": {
          "description": "AF2 + ProteinMPNN",
          "name": "binder-design",
          "pipeline": {
            "nodes": {
              "af2": {
                "inputs": {
                  "sequence": [
                    {
                      "node": "target"
                    }
                  ]
                },
                "kind": "tool",
                "tool": "tamarind://alphafold"
              },
              "target": {
                "flow": "molecule",
                "kind": "user_input",
                "metadata": {
                  "defaultGroup": "3f8a1c2e-5b7d-4e9f-a1b2-c3d4e5f6a7b8"
                },
                "molecule_type": "protein"
              }
            },
            "schema_version": "1.0"
          }
        }
      },
      "PublicCustomTool": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "displayName": {
            "type": "string",
            "title": "Displayname"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "functions": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Functions"
          },
          "status": {
            "$ref": "#/components/schemas/PublicToolStatus"
          },
          "gpuType": {
            "type": "string",
            "enum": [
              "None",
              "T4",
              "L4",
              "L40S",
              "A10",
              "A100"
            ],
            "title": "Gputype"
          },
          "memory": {
            "type": "string",
            "enum": [
              "8Gi",
              "12Gi",
              "24Gi",
              "32Gi",
              "48Gi",
              "64Gi",
              "90Gi",
              "96Gi",
              "180Gi"
            ],
            "title": "Memory"
          },
          "cpu": {
            "type": "integer",
            "title": "Cpu"
          },
          "homeDiskGi": {
            "type": "integer",
            "title": "Homediskgi"
          },
          "maxRuntimeSeconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Maxruntimeseconds"
          },
          "hasSource": {
            "type": "boolean",
            "title": "Hassource"
          },
          "sourceHash": {
            "type": "string",
            "title": "Sourcehash"
          },
          "connectionError": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Connectionerror"
          },
          "published": {
            "type": "boolean",
            "title": "Published"
          },
          "autoPublish": {
            "type": "boolean",
            "title": "Autopublish"
          },
          "defaultVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaultversion"
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          },
          "updatedAt": {
            "type": "string",
            "title": "Updatedat"
          },
          "canEdit": {
            "type": "boolean",
            "title": "Canedit"
          },
          "canDeploy": {
            "type": "boolean",
            "title": "Candeploy"
          }
        },
        "type": "object",
        "required": [
          "name",
          "displayName",
          "description",
          "functions",
          "status",
          "gpuType",
          "memory",
          "cpu",
          "homeDiskGi",
          "maxRuntimeSeconds",
          "hasSource",
          "sourceHash",
          "connectionError",
          "published",
          "autoPublish",
          "defaultVersion",
          "createdAt",
          "updatedAt",
          "canEdit",
          "canDeploy"
        ],
        "title": "PublicCustomTool"
      },
      "PublicCustomToolPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicCustomTool"
            },
            "type": "array",
            "title": "Items"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "PublicCustomToolPage"
      },
      "PublicDeleteMoleculeResponse": {
        "properties": {
          "moleculeId": {
            "type": "string",
            "title": "Moleculeid"
          },
          "deleted": {
            "type": "boolean",
            "title": "Deleted"
          }
        },
        "type": "object",
        "required": [
          "moleculeId",
          "deleted"
        ],
        "title": "PublicDeleteMoleculeResponse"
      },
      "PublicDeployRequest": {
        "properties": {
          "carryForwardFromVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Carryforwardfromversion"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicDeployRequest"
      },
      "PublicDeployResult": {
        "properties": {
          "versionName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Versionname"
          },
          "ref": {
            "type": "string",
            "title": "Ref"
          },
          "path": {
            "type": "string",
            "enum": [
              "noop",
              "saved",
              "building"
            ],
            "title": "Path"
          }
        },
        "type": "object",
        "required": [
          "versionName",
          "ref",
          "path"
        ],
        "title": "PublicDeployResult"
      },
      "PublicDiagnostic": {
        "properties": {
          "code": {
            "$ref": "#/components/schemas/DiagnosticCode"
          },
          "severity": {
            "$ref": "#/components/schemas/Severity"
          },
          "node": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Node"
          },
          "field": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Field"
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message"
          }
        },
        "type": "object",
        "required": [
          "code",
          "severity",
          "node"
        ],
        "title": "PublicDiagnostic"
      },
      "PublicDuplicateTemplateRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "version": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "A version handle e.g. 'v3'; absent -> default."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicDuplicateTemplateRequest",
        "description": "Body for `POST /templates/{templateId}/duplicate`.\n\nBoth fields are optional; `{}` is a valid body.\n\nVERSIONS ONLY — never the working draft. A draft is mutable and unversioned, so there is no\nstable thing for an API client to reference (\"the draft as of now\" isn't expressible) and it\nmay be a teammate's mid-edit graph. So `version` omitted resolves to the published version if\none is pinned, else the latest SAVED version. This is the one place the API deliberately\ndiffers from the in-app menu, which forks the draft because the user can see it.",
        "example": {
          "name": "binder-design v2 experiment",
          "version": "v2"
        }
      },
      "PublicFastaMode": {
        "type": "string",
        "enum": [
          "one-entity-per-file",
          "one-entity-per-header"
        ],
        "title": "PublicFastaMode",
        "description": "The public spelling of the ingestion worker's FASTA split modes."
      },
      "PublicFieldType": {
        "type": "string",
        "enum": [
          "string",
          "integer",
          "float",
          "boolean",
          "category",
          "chain"
        ],
        "title": "PublicFieldType",
        "description": "The spec's `FieldType`.\n\nNOTE `chain` is a MEMBER of this enum, not a separate axis: a schema's `fields`\nlist interleaves scalar fields and chain fields, and `type == \"chain\"` is what\ndistinguishes them."
      },
      "PublicFileBinding": {
        "properties": {
          "file": {
            "type": "string",
            "title": "File",
            "description": "A file path (relative to your user folder)."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "file"
        ],
        "title": "PublicFileBinding"
      },
      "PublicFileFormat": {
        "type": "string",
        "enum": [
          "auto",
          "csv",
          "fasta",
          "sdf",
          "pdb",
          "zip",
          "sdf_zip"
        ],
        "title": "PublicFileFormat",
        "description": "The spec's `FileFormat` — a STRICT SUBSET of the internal\n`MoleculeFileFormat`, which also carries `cif`/`mmcif`. The public API does not\ndocument those, so they aren't accepted here; `auto` still detects anything the\nworker can read."
      },
      "PublicFileImportRequest": {
        "properties": {
          "groupId": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Groupid"
          },
          "fileName": {
            "type": "string",
            "maxLength": 512,
            "minLength": 1,
            "title": "Filename"
          },
          "fileFormat": {
            "$ref": "#/components/schemas/PublicFileFormat",
            "default": "auto"
          },
          "sizeBytes": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 2147483648,
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Sizebytes",
            "description": "CSV imports (including `fileFormat: auto` with a `.csv` filename) may be up to 2 GiB. All other formats, including files left for content-based auto-detection, are limited to 16 MiB."
          },
          "columnMapping": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Columnmapping"
          },
          "chainMapping": {
            "anyOf": [
              {
                "additionalProperties": {
                  "$ref": "#/components/schemas/PublicChainMappingEntry"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Chainmapping"
          },
          "fastaMode": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicFastaMode"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "groupId",
          "fileName"
        ],
        "title": "PublicFileImportRequest",
        "description": "The spec's `FileImportRequest`."
      },
      "PublicFileImportStart": {
        "properties": {
          "importId": {
            "type": "string",
            "title": "Importid"
          },
          "uploadUrl": {
            "type": "string",
            "title": "Uploadurl"
          },
          "uploadMethod": {
            "type": "string",
            "const": "PUT",
            "title": "Uploadmethod",
            "default": "PUT"
          },
          "uploadHeaders": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "title": "Uploadheaders"
          },
          "groupName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupname"
          },
          "expiresInSeconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresinseconds"
          }
        },
        "type": "object",
        "required": [
          "importId",
          "uploadUrl",
          "uploadHeaders",
          "groupName",
          "expiresInSeconds"
        ],
        "title": "PublicFileImportStart"
      },
      "PublicGroup": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "displayName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Displayname"
          },
          "matchedOn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Matchedon"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "moleculeCount": {
            "type": "integer",
            "title": "Moleculecount"
          },
          "schemaId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Schemaid"
          },
          "source": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicGroupSource"
              },
              {
                "type": "null"
              }
            ]
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags"
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata"
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          },
          "updatedAt": {
            "type": "string",
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "displayName",
          "matchedOn",
          "type",
          "status",
          "moleculeCount",
          "schemaId",
          "source",
          "tags",
          "metadata",
          "createdAt",
          "updatedAt"
        ],
        "title": "PublicGroup",
        "description": "The spec's `Group` — a named collection of molecules.\n\nMolecule-only vocabulary: `moleculeCount`, never the internal `complexCount`."
      },
      "PublicGroupPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicGroup"
            },
            "type": "array",
            "title": "Items"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "title": "PublicGroupPage"
      },
      "PublicGroupSource": {
        "properties": {
          "jobId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Jobid"
          },
          "toolName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Toolname"
          }
        },
        "type": "object",
        "required": [
          "jobId",
          "toolName"
        ],
        "title": "PublicGroupSource",
        "description": "`Group.source` — set when the group is a job's output."
      },
      "PublicImportStatus": {
        "properties": {
          "importId": {
            "type": "string",
            "title": "Importid"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "groupId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupid"
          },
          "groupName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupname"
          },
          "fileName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Filename"
          },
          "fileFormat": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fileformat"
          },
          "moleculeIds": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Moleculeids"
          },
          "moleculeCount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Moleculecount"
          }
        },
        "type": "object",
        "required": [
          "importId",
          "status",
          "groupId",
          "groupName",
          "fileName",
          "fileFormat",
          "moleculeIds",
          "moleculeCount"
        ],
        "title": "PublicImportStatus"
      },
      "PublicInputSlot": {
        "properties": {
          "node": {
            "type": "string",
            "title": "Node",
            "description": "The stable input-node id you bind to."
          },
          "flow": {
            "$ref": "#/components/schemas/Flow"
          },
          "moleculeType": {
            "$ref": "#/components/schemas/MoleculeClass"
          },
          "requiresStructure": {
            "type": "boolean",
            "title": "Requiresstructure"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "chains": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Chains"
          },
          "chainLabels": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "title": "Chainlabels"
          },
          "residueFields": {
            "items": {
              "$ref": "#/components/schemas/PublicResidueField"
            },
            "type": "array",
            "title": "Residuefields"
          }
        },
        "type": "object",
        "required": [
          "node",
          "flow",
          "moleculeType",
          "requiresStructure",
          "label",
          "chains",
          "chainLabels",
          "residueFields"
        ],
        "title": "PublicInputSlot"
      },
      "PublicJobDetail": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Opaque job id. Pass it to `GET /v1/jobs/{job_id}`."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "The name supplied when the job or batch was submitted."
          },
          "kind": {
            "type": "string",
            "enum": [
              "standalone",
              "batch"
            ],
            "title": "Kind",
            "description": "Whether this is one job or the parent of a submitted batch."
          },
          "tool": {
            "$ref": "#/components/schemas/PublicJobTool",
            "description": "The tool and schema version used by the job."
          },
          "status": {
            "$ref": "#/components/schemas/PublicJobStatus",
            "description": "The job's current lifecycle state."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat",
            "description": "When the job was created, as an ISO 8601 timestamp."
          },
          "startedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Startedat",
            "description": "When execution started, as an ISO 8601 timestamp; null while queued."
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat",
            "description": "When the job reached a terminal state, as an ISO 8601 timestamp."
          },
          "batchId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Batchid",
            "description": "The batch identifier for a batch parent; null for a standalone job."
          },
          "usage": {
            "$ref": "#/components/schemas/PublicJobUsage",
            "description": "The compute usage recorded for this job."
          },
          "settings": {
            "additionalProperties": true,
            "type": "object",
            "title": "Settings",
            "description": "Submitted run settings that are safe to return and are not biological inputs."
          },
          "inputs": {
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/PublicSequenceInput"
                },
                {
                  "$ref": "#/components/schemas/PublicSmilesInput"
                },
                {
                  "$ref": "#/components/schemas/PublicCcdInput"
                },
                {
                  "$ref": "#/components/schemas/PublicStructureInput"
                },
                {
                  "$ref": "#/components/schemas/PublicUnavailableInput"
                }
              ],
              "discriminator": {
                "propertyName": "kind",
                "mapping": {
                  "ccd": "#/components/schemas/PublicCcdInput",
                  "sequence": "#/components/schemas/PublicSequenceInput",
                  "smiles": "#/components/schemas/PublicSmilesInput",
                  "structure": "#/components/schemas/PublicStructureInput",
                  "unavailable": "#/components/schemas/PublicUnavailableInput"
                }
              }
            },
            "type": "array",
            "title": "Inputs",
            "description": "Submitted biological inputs, represented by their specific input type."
          },
          "stoppedReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stoppedreason",
            "description": "Why the job stopped; present only when `status` is `stopped`."
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "tool",
          "status",
          "createdAt",
          "startedAt",
          "completedAt",
          "batchId",
          "usage",
          "settings",
          "inputs",
          "stoppedReason"
        ],
        "title": "PublicJobDetail"
      },
      "PublicJobPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicJobSummary"
            },
            "type": "array",
            "title": "Items",
            "description": "Jobs in this page, newest first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Pass this value as `cursor` to fetch the next page; null on the last page."
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "title": "PublicJobPage"
      },
      "PublicJobStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "succeeded",
          "failed",
          "stopped"
        ],
        "title": "PublicJobStatus"
      },
      "PublicJobSummary": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Opaque job id. Pass it to `GET /v1/jobs/{job_id}`."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "The name supplied when the job or batch was submitted."
          },
          "kind": {
            "type": "string",
            "enum": [
              "standalone",
              "batch"
            ],
            "title": "Kind",
            "description": "Whether this is one job or the parent of a submitted batch."
          },
          "tool": {
            "$ref": "#/components/schemas/PublicJobTool",
            "description": "The tool and schema version used by the job."
          },
          "status": {
            "$ref": "#/components/schemas/PublicJobStatus",
            "description": "The job's current lifecycle state."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat",
            "description": "When the job was created, as an ISO 8601 timestamp."
          },
          "startedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Startedat",
            "description": "When execution started, as an ISO 8601 timestamp; null while queued."
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat",
            "description": "When the job reached a terminal state, as an ISO 8601 timestamp."
          },
          "batchId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Batchid",
            "description": "The batch identifier for a batch parent; null for a standalone job."
          },
          "usage": {
            "$ref": "#/components/schemas/PublicJobUsage",
            "description": "The compute usage recorded for this job."
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "tool",
          "status",
          "createdAt",
          "startedAt",
          "completedAt",
          "batchId",
          "usage"
        ],
        "title": "PublicJobSummary"
      },
      "PublicJobTool": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "The tool type that ran the job."
          },
          "version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "The exact tool schema version used by the job, when it was recorded."
          }
        },
        "type": "object",
        "required": [
          "id",
          "version"
        ],
        "title": "PublicJobTool"
      },
      "PublicJobUsage": {
        "properties": {
          "weightedHours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Weightedhours",
            "description": "Compute usage normalized by runtime and hardware tier; null until available."
          }
        },
        "type": "object",
        "required": [
          "weightedHours"
        ],
        "title": "PublicJobUsage"
      },
      "PublicLiteralInputSource": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "literal",
            "title": "Kind",
            "description": "The input value was stored directly on the job."
          }
        },
        "type": "object",
        "required": [
          "kind"
        ],
        "title": "PublicLiteralInputSource"
      },
      "PublicMolecule": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "entity": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "title": "Entity"
          },
          "chainMapping": {
            "additionalProperties": {
              "$ref": "#/components/schemas/MoleculeChainInfo"
            },
            "type": "object",
            "title": "Chainmapping"
          },
          "files": {
            "additionalProperties": {
              "items": {
                "$ref": "#/components/schemas/MoleculeFileEntry"
              },
              "type": "array"
            },
            "type": "object",
            "title": "Files"
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata"
          },
          "truncated": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Truncated"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "addedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Addedat"
          },
          "origin": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicMoleculeOrigin"
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source"
          },
          "groups": {
            "items": {
              "$ref": "#/components/schemas/PublicGroup"
            },
            "type": "array",
            "title": "Groups"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags"
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Notes"
          },
          "hasStructure": {
            "type": "boolean",
            "title": "Hasstructure"
          },
          "matchedOn": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Matchedon"
          },
          "sortGroup": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicMoleculeSortGroup"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "type",
          "entity",
          "chainMapping",
          "files",
          "metadata",
          "truncated",
          "createdAt",
          "addedAt",
          "origin",
          "source",
          "groups",
          "tags",
          "notes",
          "hasStructure",
          "matchedOn"
        ],
        "title": "PublicMolecule",
        "description": "One molecule, everything inline — no follow-up call to read scores."
      },
      "PublicMoleculeBinding": {
        "properties": {
          "group": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Group",
            "description": "An existing molecules group id."
          },
          "sequences": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sequences",
            "description": "Raw protein or nucleic-acid sequences to make a group from."
          },
          "smiles": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smiles",
            "description": "Raw small-molecule SMILES to make a group from."
          },
          "pdbs": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pdbs",
            "description": "Uploaded .pdb file paths (relative to your user folder) to make a protein or nucleic-acid group from."
          },
          "sdfs": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sdfs",
            "description": "Uploaded .sdf file paths (relative to your user folder) to make a group from."
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Name for the group created from raw values (auto if omitted)."
          },
          "chainMapping": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Chainmapping",
            "description": "Optional; defaults to identity. referenceChain -> yourChain — only needed for an existing template whose reference chain IDs differ from your molecule's (for an inline pipeline your molecule IS the reference, so omit it)."
          },
          "residuesByChain": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Residuesbychain",
            "description": "referenceChain -> residue selection."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicMoleculeBinding",
        "description": "A molecule binding. Provide the molecules ONE of these ways (exactly one):\n\n- `group` — an existing molecules group id, OR\n- `sequences` — raw protein or nucleic-acid sequences, OR\n- `smiles` — raw small-molecule SMILES, OR\n- `pdbs` / `sdfs` — paths (relative to your user folder) of already-uploaded structure files.\n\nFor the raw-value forms the server creates a molecules group for you (optionally named via `name`),\nthen binds it — so you don't have to pre-create one. The target input node declares the polymer\ntype for sequences/PDBs; SMILES/SDFs require a small-molecule target."
      },
      "PublicMoleculeInput": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MoleculeType"
              },
              {
                "type": "null"
              }
            ]
          },
          "entity": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "maxProperties": 64,
            "minProperties": 1,
            "title": "Entity"
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 64,
            "title": "Tags"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "entity"
        ],
        "title": "PublicMoleculeInput",
        "description": "The spec's `MoleculeInput` — one molecule to create."
      },
      "PublicMoleculeInputSource": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "molecule",
            "title": "Kind",
            "description": "The input was resolved from the molecules database."
          },
          "moleculeId": {
            "type": "string",
            "title": "Moleculeid",
            "description": "The molecule's id."
          },
          "groupId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupid",
            "description": "The source molecule group, when known."
          },
          "fileId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fileid",
            "description": "The source file, when known."
          },
          "chains": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Chains",
            "description": "The molecule chain ids used by this input."
          }
        },
        "type": "object",
        "required": [
          "kind",
          "moleculeId",
          "groupId",
          "fileId",
          "chains"
        ],
        "title": "PublicMoleculeInputSource"
      },
      "PublicMoleculeOrigin": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type"
          },
          "jobId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Jobid"
          },
          "jobType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Jobtype"
          }
        },
        "type": "object",
        "required": [
          "type",
          "jobId",
          "jobType"
        ],
        "title": "PublicMoleculeOrigin",
        "description": "`Molecule.origin` — how this molecule came to exist.\n\n`type` is the `complexes.origin_type` provenance class and is ALWAYS present (an\nuploaded molecule is `user_import`). `jobId`/`jobType` name the producing job/batch\nfor a tool-produced molecule; BOTH are null for an upload — an upload has no job, and\nwe do not fabricate one. Read-only, projected from columns that already exist (no\nmigration)."
      },
      "PublicMoleculePage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicMolecule"
            },
            "type": "array",
            "title": "Items"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          },
          "mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mode"
          },
          "scanProgress": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scanprogress"
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor",
          "mode",
          "scanProgress"
        ],
        "title": "PublicMoleculePage",
        "description": "The spec's `MoleculePage` — `{items, nextCursor}` plus the three\nSEARCH-MODE fields below, and nothing else.\n\nDeliberately NOT `Page[PublicMolecule]`: the generic carries a field\n(`sortedServerSide`, the internal sheet's score-cap fallback flag) that the\npublished contract doesn't declare and no public caller can act on. The\nenvelope grew for `mode=sequence`, which is a CHUNKED scan and therefore has\nto say two things a plain page cannot: which search actually ran, and how far\nthrough the scan this page got."
      },
      "PublicMoleculeSortGroup": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "title": "PublicMoleculeSortGroup",
        "description": "`Molecule.sortGroup` — the group this row was ORDERED BY, under `sortBy=groupName`.\n\nA molecule can be in many of your groups, so `sortBy=groupName` has to rank it by ONE\nof them: the alphabetically first EFFECTIVE (displayed) name across all your in-scope\nmemberships. That group is what makes a group's rows arrive contiguously, and it is\nthe group a grouped presentation should file the row under.\n\nIt is served because the inline `groups` list cannot be trusted to contain it: that\nlist is CAPPED and selected by membership recency, so a molecule in more groups than\nthe cap can be ranked by a group the response never carries. Re-deriving the section\nby name-sorting `groups` then files the row under the wrong heading — silently, and\nwith no way for a client to tell.\n\n`name` is the EFFECTIVE name (the rename label when one exists, else the canonical\none) — the exact string the ordering compared, so a section header built from it\ncannot disagree with the position the row was served in. That makes it the\n`displayName`-preferring sibling of `Group.name`, which is always the raw canonical\ncolumn; for a group that was never renamed the two are identical."
      },
      "PublicPublishRequest": {
        "properties": {
          "version": {
            "type": "string",
            "minLength": 1,
            "title": "Version",
            "description": "The version handle to publish e.g. 'v1' (from a prior response's version)."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "version"
        ],
        "title": "PublicPublishRequest",
        "example": {
          "version": "v1"
        }
      },
      "PublicPublishResponse": {
        "properties": {
          "templateId": {
            "type": "string",
            "title": "Templateid"
          },
          "isPublished": {
            "type": "boolean",
            "title": "Ispublished"
          },
          "publishedVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Publishedversion",
            "description": "The published version handle e.g. 'v1'."
          }
        },
        "type": "object",
        "required": [
          "templateId",
          "isPublished",
          "publishedVersion"
        ],
        "title": "PublicPublishResponse"
      },
      "PublicRecommendationInput": {
        "properties": {
          "id": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Id",
            "description": "Your label for this input. Used to point at it in errors."
          },
          "kind": {
            "type": "string",
            "enum": [
              "sequence",
              "structure",
              "ligand",
              "msa",
              "template",
              "file",
              "other"
            ],
            "title": "Kind",
            "description": "What this input is."
          },
          "format": {
            "type": "string",
            "maxLength": 40,
            "minLength": 1,
            "title": "Format",
            "description": "How it is encoded, e.g. `fasta`, `pdb`, `smiles`."
          },
          "role": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ],
            "title": "Role",
            "description": "Its part in the complex, e.g. `antibody` or `antigen`. Sharpens the benchmark match."
          },
          "sequence": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 10000,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Sequence",
            "description": "One protein chain."
          },
          "smiles": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 10000,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Smiles",
            "description": "A ligand, as SMILES."
          },
          "ccd": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 8,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Ccd",
            "description": "A ligand, as a PDB component id."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "id",
          "kind",
          "format"
        ],
        "title": "PublicRecommendationInput",
        "description": "What you send depends on `kind`:\n\n- `sequence` — include `sequence`, not `smiles` or `ccd`\n- `ligand` — include `smiles` or `ccd`, never both"
      },
      "PublicRecommendationProvenance": {
        "properties": {
          "catalogVersion": {
            "type": "string",
            "title": "Catalogversion",
            "description": "The tool-catalogue release the candidates came from."
          },
          "evidenceVersion": {
            "type": "string",
            "title": "Evidenceversion",
            "description": "The benchmark release the claims resolve against. A sentinel such as `benchmark-unconfigured` means no benchmark informed this answer, and every tool will be `weak`."
          },
          "classifierVersion": {
            "type": "string",
            "title": "Classifierversion",
            "description": "The classifier that decided which task this request is."
          }
        },
        "type": "object",
        "required": [
          "catalogVersion",
          "evidenceVersion",
          "classifierVersion"
        ],
        "title": "PublicRecommendationProvenance",
        "description": "What produced this answer. Present on every response, including an abstention."
      },
      "PublicRecommendedTool": {
        "properties": {
          "toolId": {
            "type": "string",
            "title": "Toolid",
            "description": "The tool to run, as named by the tool catalogue."
          },
          "evidenceStrength": {
            "type": "string",
            "enum": [
              "strong",
              "moderate",
              "weak"
            ],
            "title": "Evidencestrength",
            "description": "How strong the EVIDENCE about this tool is — not how highly it is recommended. Quality is carried by the ORDER. `strong` means the benchmark separates this tool cleanly, which can be cleanly better OR cleanly worse: the last tool in the list can be `strong`. `moderate` means it is statistically tied with another candidate or its benchmark carries a leakage flag. `weak` means UN-BENCHMARKED — nothing was measured, which is not the same as measuring badly. `reasonCodes` says which."
          },
          "reason": {
            "type": "string",
            "title": "Reason",
            "description": "Why this tool, in prose."
          },
          "reasonCodes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Reasoncodes",
            "description": "Machine-readable grounds for `evidenceStrength`, e.g. `un_benchmarked`, `statistically_tied`, `benchmark_leakage_flag`, `benchmarked_clear_separation`. Branch on these rather than on `reason`."
          },
          "evidenceClaims": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Evidenceclaims",
            "description": "Identifiers for the benchmark claims this rests on, resolvable against `provenance.evidenceVersion`. Empty when the tool is un-benchmarked."
          }
        },
        "type": "object",
        "required": [
          "toolId",
          "evidenceStrength",
          "reason",
          "reasonCodes",
          "evidenceClaims"
        ],
        "title": "PublicRecommendedTool",
        "description": "One tool, in recommended order. The ORDER is the recommendation."
      },
      "PublicRemoveMoleculesFromGroupRequest": {
        "properties": {
          "groupId": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Groupid"
          },
          "moleculeIds": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 1000,
            "minItems": 1,
            "title": "Moleculeids"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "groupId",
          "moleculeIds"
        ],
        "title": "PublicRemoveMoleculesFromGroupRequest",
        "description": "Body for `POST /molecules/remove`: the group to detach FROM plus the molecules\nto detach — the group id travels in the body alongside the ids. Same `moleculeIds` cap (maxItems, a real\nstatement bound — every id is a bound `uuid[]` parameter, never inlined)."
      },
      "PublicRemoveMoleculesResponse": {
        "properties": {
          "removedIds": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Removedids"
          },
          "removedCount": {
            "type": "integer",
            "title": "Removedcount"
          }
        },
        "type": "object",
        "required": [
          "removedIds",
          "removedCount"
        ],
        "title": "PublicRemoveMoleculesResponse"
      },
      "PublicResidueField": {
        "properties": {
          "node": {
            "type": "string",
            "title": "Node"
          },
          "field": {
            "type": "string",
            "title": "Field"
          },
          "multichain": {
            "type": "boolean",
            "title": "Multichain"
          },
          "targetsChains": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Targetschains"
          }
        },
        "type": "object",
        "required": [
          "node",
          "field",
          "multichain",
          "targetsChains"
        ],
        "title": "PublicResidueField"
      },
      "PublicRun": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "templateId": {
            "type": "string",
            "title": "Templateid"
          },
          "templateVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Templateversion",
            "description": "The executed version handle e.g. 'v1'."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "status": {
            "$ref": "#/components/schemas/RunStatus"
          },
          "startedAt": {
            "type": "string",
            "title": "Startedat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          },
          "inputs": {
            "additionalProperties": true,
            "type": "object",
            "title": "Inputs",
            "description": "The recorded inputs (input-node id -> {group} or {file})."
          },
          "steps": {
            "items": {
              "$ref": "#/components/schemas/PublicStep"
            },
            "type": "array",
            "title": "Steps"
          }
        },
        "type": "object",
        "required": [
          "id",
          "templateId",
          "templateVersion",
          "name",
          "source",
          "status",
          "startedAt",
          "completedAt",
          "inputs",
          "steps"
        ],
        "title": "PublicRun"
      },
      "PublicRunPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicRunSummary"
            },
            "type": "array",
            "title": "Items"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "title": "PublicRunPage"
      },
      "PublicRunResults": {
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "ready",
              "failed"
            ],
            "title": "Status",
            "description": "`processing` (building / not finished), `ready` (download `url` set), or `failed`."
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url",
            "description": "A short-lived signed download URL — present only when `status` is `ready`."
          },
          "node": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Node",
            "description": "The scoped step id, echoed back when `?node=` was supplied."
          }
        },
        "type": "object",
        "required": [
          "status",
          "url",
          "node"
        ],
        "title": "PublicRunResults",
        "description": "`GET /runs/results` — the run's (or one node's) output ZIP, produced asynchronously.\n\nPoll this: `processing` while the archive is being built (or the run/step isn't finished yet),\n`ready` with a short-lived signed `url` once it's available, `failed` if the build failed. Polling\nis idempotent — it never starts a duplicate build.\n\n`url`/`node` carry NO default (this surface's required-at-construction convention, see the module\ndocstring): both are always present in the response — `null` when not applicable (`url` unless\n`ready`; `node` unless a step was requested) — so a client can rely on the stable key set."
      },
      "PublicRunSummary": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "templateId": {
            "type": "string",
            "title": "Templateid"
          },
          "templateVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Templateversion",
            "description": "The executed version handle e.g. 'v1'."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "status": {
            "$ref": "#/components/schemas/RunStatus"
          },
          "startedAt": {
            "type": "string",
            "title": "Startedat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "templateId",
          "templateVersion",
          "name",
          "source",
          "status",
          "startedAt",
          "completedAt"
        ],
        "title": "PublicRunSummary"
      },
      "PublicSchema": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "fields": {
            "items": {
              "$ref": "#/components/schemas/PublicSchemaField"
            },
            "type": "array",
            "title": "Fields"
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "fields",
          "createdAt"
        ],
        "title": "PublicSchema",
        "description": "The spec's `Schema`."
      },
      "PublicSchemaField": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name"
          },
          "type": {
            "$ref": "#/components/schemas/PublicFieldType",
            "default": "string"
          },
          "required": {
            "type": "boolean",
            "title": "Required",
            "default": false
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "units": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Units"
          },
          "options": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "maxItems": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Options",
            "description": "Allowed values for a `category` field. REQUIRED (non-empty) when `type` is `category`, and must be omitted for every other type."
          },
          "chainType": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicChainType"
              },
              {
                "type": "null"
              }
            ]
          },
          "chainTag": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PublicChainTag"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name"
        ],
        "title": "PublicSchemaField",
        "description": "The spec's `SchemaField` — one field in a schema.\n\nA RequestModel (extra='forbid') even though it also appears on responses: the\nfield names are already the wire spelling, so no alias generator is needed, and\nforbidding extras means a typo'd `chaintype` 422s at create instead of being\nsilently stored in the JSONB and never enforced.\n\n`type` defaults to `string` per the spec. `chain` is one of its values — a\nchain field's `name` IS the chain id (`H`, `L`, `A`), matching the keys of a\nmolecule's `entity` map."
      },
      "PublicSchemaPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicSchema"
            },
            "type": "array",
            "title": "Items"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "title": "PublicSchemaPage"
      },
      "PublicSequenceInput": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "sequence",
            "title": "Kind",
            "description": "A protein or nucleic-acid sequence input."
          },
          "parameter": {
            "type": "string",
            "title": "Parameter",
            "description": "The tool setting that received this input."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "The submitted sequence name, when provided."
          },
          "sequence": {
            "type": "string",
            "title": "Sequence",
            "description": "The submitted biological sequence."
          },
          "source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicLiteralInputSource"
              },
              {
                "$ref": "#/components/schemas/PublicMoleculeInputSource"
              }
            ],
            "title": "Source",
            "description": "Where this input value came from.",
            "discriminator": {
              "propertyName": "kind",
              "mapping": {
                "literal": "#/components/schemas/PublicLiteralInputSource",
                "molecule": "#/components/schemas/PublicMoleculeInputSource"
              }
            }
          }
        },
        "type": "object",
        "required": [
          "kind",
          "parameter",
          "name",
          "sequence",
          "source"
        ],
        "title": "PublicSequenceInput"
      },
      "PublicSmilesInput": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "smiles",
            "title": "Kind",
            "description": "A small molecule represented as SMILES."
          },
          "parameter": {
            "type": "string",
            "title": "Parameter",
            "description": "The tool setting that received this input."
          },
          "smiles": {
            "type": "string",
            "title": "Smiles",
            "description": "The submitted SMILES string."
          },
          "source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicLiteralInputSource"
              },
              {
                "$ref": "#/components/schemas/PublicMoleculeInputSource"
              }
            ],
            "title": "Source",
            "description": "Where this input value came from.",
            "discriminator": {
              "propertyName": "kind",
              "mapping": {
                "literal": "#/components/schemas/PublicLiteralInputSource",
                "molecule": "#/components/schemas/PublicMoleculeInputSource"
              }
            }
          }
        },
        "type": "object",
        "required": [
          "kind",
          "parameter",
          "smiles",
          "source"
        ],
        "title": "PublicSmilesInput"
      },
      "PublicStatus": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status"
          }
        },
        "type": "object",
        "required": [
          "status"
        ],
        "title": "PublicStatus"
      },
      "PublicStep": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "node": {
            "type": "string",
            "title": "Node",
            "description": "The stable IR node id."
          },
          "label": {
            "type": "string",
            "title": "Label"
          },
          "type": {
            "type": "string",
            "title": "Type"
          },
          "status": {
            "$ref": "#/components/schemas/StepStatus"
          },
          "startedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Startedat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          },
          "outputCount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Outputcount"
          },
          "jobsTotal": {
            "type": "integer",
            "title": "Jobstotal"
          },
          "jobsComplete": {
            "type": "integer",
            "title": "Jobscomplete"
          },
          "outputGroup": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Outputgroup",
            "description": "The molecules group id this step produced."
          }
        },
        "type": "object",
        "required": [
          "id",
          "node",
          "label",
          "type",
          "status",
          "startedAt",
          "completedAt",
          "outputCount",
          "jobsTotal",
          "jobsComplete",
          "outputGroup"
        ],
        "title": "PublicStep"
      },
      "PublicStepMolecule": {
        "properties": {
          "complexId": {
            "type": "string",
            "title": "Complexid"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "moleculeType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Moleculetype"
          },
          "sequence": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sequence",
            "description": "The ':'-joined chain sequences."
          },
          "scores": {
            "additionalProperties": true,
            "type": "object",
            "title": "Scores",
            "description": "Per-tool scores keyed by tool."
          },
          "hasStructure": {
            "type": "boolean",
            "title": "Hasstructure"
          }
        },
        "type": "object",
        "required": [
          "complexId",
          "name",
          "moleculeType",
          "sequence",
          "scores",
          "hasStructure"
        ],
        "title": "PublicStepMolecule",
        "description": "One molecule a step PRODUCED.\n\nRead from the step's passing outputs directly, NOT from `PublicStep.outputGroup` — which is why\nthis exists. A step's `outputGroup` is the group the step MINTED, and a step that enriches its\ninputs in place (scoring, structure prediction) mints none: its molecules never moved, so they\nstay in the group they came from and `outputGroup` is correctly null. A filter step has no group\neither — its survivors exist only as outputs. Reading results by group therefore reports\n\"produced nothing\" for exactly the steps that produced the most interesting thing."
      },
      "PublicStepMoleculePage": {
        "properties": {
          "molecules": {
            "items": {
              "$ref": "#/components/schemas/PublicStepMolecule"
            },
            "type": "array",
            "title": "Molecules"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Pass as `cursor` for the next page."
          }
        },
        "type": "object",
        "required": [
          "molecules",
          "nextCursor"
        ],
        "title": "PublicStepMoleculePage"
      },
      "PublicStructureInput": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "structure",
            "title": "Kind",
            "description": "A submitted molecular structure file."
          },
          "parameter": {
            "type": "string",
            "title": "Parameter",
            "description": "The tool setting that received this input."
          },
          "fileName": {
            "type": "string",
            "title": "Filename",
            "description": "The submitted structure file name."
          },
          "source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicLiteralInputSource"
              },
              {
                "$ref": "#/components/schemas/PublicMoleculeInputSource"
              }
            ],
            "title": "Source",
            "description": "Where this input value came from.",
            "discriminator": {
              "propertyName": "kind",
              "mapping": {
                "literal": "#/components/schemas/PublicLiteralInputSource",
                "molecule": "#/components/schemas/PublicMoleculeInputSource"
              }
            }
          }
        },
        "type": "object",
        "required": [
          "kind",
          "parameter",
          "fileName",
          "source"
        ],
        "title": "PublicStructureInput"
      },
      "PublicSubmitPipelineRequest": {
        "properties": {
          "pipeline": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PipelineIR"
              },
              {
                "type": "null"
              }
            ],
            "description": "INLINE mode: a full pipeline IR. Mutually exclusive with `templateId`."
          },
          "templateId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Templateid",
            "description": "REFERENCE mode: an existing template id to run."
          },
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name",
            "description": "Name for this pipeline. When `runName` is omitted, the run's JobName is derived from this (spaces removed, a random suffix appended for uniqueness)."
          },
          "runName": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Runname",
            "description": "Optional explicit JobName for THIS run. Spaces are replaced with underscores; used verbatim otherwise (no random suffix). Omit to auto-generate a unique JobName from `name`."
          },
          "version": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "REFERENCE mode: a version handle e.g. 'v1'; absent -> default."
          },
          "bindings": {
            "additionalProperties": {
              "$ref": "#/components/schemas/PublicBinding"
            },
            "type": "object",
            "maxProperties": 2048,
            "title": "Bindings",
            "description": "One binding per input slot, keyed by the slot's input-node id. Bindings may be defined as an array of sequences, smiles, or sdf/pdb files (uploaded using the /upload endpoint), or an existing molecule group id (created using /molecules/groups below)."
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings",
            "description": "REFERENCE mode: per-node setting overrides `{nodeId: {settingKey: value}}`, limited to the template's editable settings."
          },
          "source": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Source"
              },
              {
                "type": "null"
              }
            ],
            "description": "Run source; defaults to production.",
            "default": "production"
          },
          "project": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Project",
            "description": "Organization project id to stamp on jobs this run creates."
          },
          "idempotencyKey": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Idempotencykey",
            "description": "Client key to safely retry a submit (≤255)."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name",
          "bindings"
        ],
        "title": "PublicSubmitPipelineRequest",
        "description": "Body for `POST /pipelines/submit` AND `POST /pipelines/validate` (identical shape). Two modes,\ndiscriminated by which of `pipeline` / `templateId` you send — exactly one is required:\n\n- INLINE: send `pipeline` (a full IR) — submit creates a template you own (unpublished) and runs\n  it; every setting is yours to set in the IR. `name` names both the created pipeline and the run.\n- REFERENCE: send `templateId` (+ optional `version`) — run an existing template; `settings`\n  overrides are limited to each tool node's `metadata.editableSettings`. `name` names the run.\n\n`name` is required and doubles as the run's display name (deduplicated per pipeline). `bindings` is\nrequired in both modes. `validate` runs the SAME body without executing/persisting.",
        "example": {
          "bindings": {
            "target": {
              "group": "3f8a1c2e-5b7d-4e9f-a1b2-c3d4e5f6a7b8"
            }
          },
          "name": "binder-design v2 experiment",
          "project": "proj_…",
          "settings": {
            "design": {
              "numSequences": 32
            }
          },
          "templateId": "3f2a1c9e-8b7d-4e6f-a1b2-c3d4e5f60718",
          "version": "v1"
        }
      },
      "PublicTemplate": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "isPublished": {
            "type": "boolean",
            "title": "Ispublished"
          },
          "publishedVersion": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Publishedversion",
            "description": "The published version handle e.g. 'v1' (null if none)."
          },
          "version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "The version handle e.g. 'v1' (null if never saved)."
          },
          "pipeline": {
            "$ref": "#/components/schemas/PipelineIR"
          },
          "inputs": {
            "items": {
              "$ref": "#/components/schemas/PublicInputSlot"
            },
            "type": "array",
            "title": "Inputs"
          },
          "versions": {
            "items": {
              "$ref": "#/components/schemas/PublicVersionSummary"
            },
            "type": "array",
            "title": "Versions",
            "description": "All saved versions, newest first."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          },
          "updatedAt": {
            "type": "string",
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "isPublished",
          "publishedVersion",
          "version",
          "pipeline",
          "inputs",
          "versions",
          "createdAt",
          "updatedAt"
        ],
        "title": "PublicTemplate"
      },
      "PublicTemplatePage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicTemplateSummary"
            },
            "type": "array",
            "title": "Items"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          }
        },
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "title": "PublicTemplatePage"
      },
      "PublicTemplateSummary": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "isPublished": {
            "type": "boolean",
            "title": "Ispublished"
          },
          "versionCount": {
            "type": "integer",
            "title": "Versioncount"
          },
          "runCount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Runcount"
          },
          "createdBy": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdby"
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          },
          "updatedAt": {
            "type": "string",
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "isPublished",
          "versionCount",
          "runCount",
          "createdBy",
          "createdAt",
          "updatedAt"
        ],
        "title": "PublicTemplateSummary"
      },
      "PublicToolRecommendation": {
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "recommend",
              "abstain"
            ],
            "title": "Action",
            "description": "`recommend` — `tools` is ranked, best first. `abstain` — no tool could be justified, `tools` is empty, and `uncertainties` says what was missing."
          },
          "summary": {
            "type": "string",
            "title": "Summary",
            "description": "A short explanation of the ranking, for a person to read."
          },
          "tools": {
            "items": {
              "$ref": "#/components/schemas/PublicRecommendedTool"
            },
            "type": "array",
            "title": "Tools",
            "description": "Ranked best-first. Empty on `abstain`."
          },
          "uncertainties": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Uncertainties",
            "description": "What the service could not establish, e.g. `no_similar_benchmark_target`, `evidence_unavailable`. Present on both outcomes."
          },
          "provenance": {
            "$ref": "#/components/schemas/PublicRecommendationProvenance"
          }
        },
        "type": "object",
        "required": [
          "action",
          "summary",
          "tools",
          "uncertainties",
          "provenance"
        ],
        "title": "PublicToolRecommendation",
        "description": "A ranked recommendation, or a reasoned refusal to make one.\n\n`abstain` is a normal outcome, not an error: it means no tool could be defended for\nthis request, and `uncertainties` says why. Callers should handle it as an answer."
      },
      "PublicToolRecommendationRequest": {
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 20000,
            "minLength": 1,
            "title": "Prompt",
            "description": "What you want to do, in your own words — e.g. 'predict the structure of this antibody-antigen complex'."
          },
          "inputs": {
            "items": {
              "$ref": "#/components/schemas/PublicRecommendationInput"
            },
            "type": "array",
            "maxItems": 32,
            "title": "Inputs",
            "description": "Sequences or ligands you already have. Optional."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "prompt"
        ],
        "title": "PublicToolRecommendationRequest",
        "description": "Ask which tool to run for a stated task."
      },
      "PublicToolStatus": {
        "type": "string",
        "enum": [
          "Draft",
          "Building",
          "Deployed"
        ],
        "title": "PublicToolStatus"
      },
      "PublicUnavailableInput": {
        "properties": {
          "kind": {
            "type": "string",
            "const": "unavailable",
            "title": "Kind",
            "description": "An input the API cannot safely return in a typed form."
          },
          "parameter": {
            "type": "string",
            "title": "Parameter",
            "description": "The tool setting that received this input."
          },
          "reason": {
            "type": "string",
            "enum": [
              "source_unavailable",
              "unsupported_legacy_input",
              "input_limit_exceeded"
            ],
            "title": "Reason",
            "description": "Why the input value is unavailable."
          }
        },
        "type": "object",
        "required": [
          "kind",
          "parameter",
          "reason"
        ],
        "title": "PublicUnavailableInput"
      },
      "PublicUpdateCustomToolRequest": {
        "properties": {
          "displayName": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Displayname"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "functions": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "maxLength": 200,
                  "minLength": 1
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Functions"
          },
          "gpuType": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "None",
                  "T4",
                  "L4",
                  "L40S",
                  "A10",
                  "A100"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Gputype"
          },
          "memory": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "8Gi",
                  "12Gi",
                  "24Gi",
                  "32Gi",
                  "48Gi",
                  "64Gi",
                  "90Gi",
                  "96Gi",
                  "180Gi"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Memory"
          },
          "cpu": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 8,
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Cpu"
          },
          "homeDiskGi": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 50,
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Homediskgi"
          },
          "autoPublish": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Autopublish"
          },
          "estTime": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Esttime"
          },
          "paperUrl": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "title": "Paperurl"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "maxLength": 200,
                  "minLength": 1
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicUpdateCustomToolRequest"
      },
      "PublicUpdateMetadataRequest": {
        "properties": {
          "properties": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Properties"
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source"
          },
          "fileId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Fileid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "DEPRECATED alias for `properties`, kept for callers written against the original v1 shape. Send `properties` instead; if both are sent, `properties` wins."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicUpdateMetadataRequest",
        "description": "The spec's `UpdateMoleculeRequest` — a PARTIAL patch across the MOLECULE and\nMEMBERSHIP tenancy grains, applied ATOMICALLY (all-or-nothing, one transaction: if any\nfield's write fails, none of them persist).\n\nEvery field is OPTIONAL and independent: an ABSENT field is left untouched, which\nis DISTINCT from a field sent as `null` (which CLEARS it, where the grain allows).\nThe fields and the grain each writes:\n\n  * `properties` (MOLECULE grain) — merge scalar annotations into the molecule's\n    metadata. Only the keys you send change; a key set to `null` REMOVES that key\n    (an absent key and a null key mean different things, so the raw dict carries\n    intent). Tool score-run entries are written by tools and are not editable here;\n    when the molecule's group is schema-bound the MERGED result must still satisfy\n    it. This is the properties-only PATCH's behaviour, unchanged.\n  * `source` (MOLECULE grain) — the id of the PARENT molecule this one was derived\n    from; `null` clears it. The parent must be visible in YOUR scope, or the write\n    is refused (404) — you cannot point a molecule at a parent you cannot see.\n  * `fileId` (MOLECULE + MEMBERSHIP grain) — a structure file to associate as this\n    membership's primary; `null` clears it. The file must already be attached to\n    this molecule in your tenant.\n  * `name` (MEMBERSHIP grain) — rename this molecule's per-group display name. A\n    name already used by another molecule in the same group is a 409 conflict (the\n    `UNIQUE (group_id, name)` constraint), never a 500.\n\nThe membership-grained writes (`name`, `fileId`) target the molecule's MOST RECENT\nin-scope group membership, matching how the group-less by-id read resolves labels."
      },
      "PublicUpdateSchemaRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "fields": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/PublicSchemaField"
                },
                "type": "array",
                "maxItems": 200,
                "minItems": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicUpdateSchemaRequest",
        "description": "The spec's `UpdateSchemaRequest` — partial. `fields` REPLACES the whole\nlist; omitted keys are left unchanged."
      },
      "PublicUploadFinalized": {
        "properties": {
          "status": {
            "type": "string",
            "const": "processing",
            "title": "Status"
          }
        },
        "type": "object",
        "required": [
          "status"
        ],
        "title": "PublicUploadFinalized"
      },
      "PublicUploadRequest": {
        "properties": {
          "groupId": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Groupid"
          },
          "chainMapping": {
            "additionalProperties": {
              "$ref": "#/components/schemas/PublicChainMappingEntry"
            },
            "type": "object",
            "title": "Chainmapping"
          },
          "molecules": {
            "items": {
              "$ref": "#/components/schemas/PublicMoleculeInput"
            },
            "type": "array",
            "maxItems": 1000,
            "minItems": 1,
            "title": "Molecules"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "groupId",
          "molecules"
        ],
        "title": "PublicUploadRequest",
        "description": "The spec's `UploadRequest`."
      },
      "PublicUploadResponse": {
        "properties": {
          "groupId": {
            "type": "string",
            "title": "Groupid"
          },
          "groupName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Groupname"
          },
          "moleculeIds": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Moleculeids"
          },
          "moleculeCount": {
            "type": "integer",
            "title": "Moleculecount"
          },
          "status": {
            "type": "string",
            "const": "pending",
            "title": "Status",
            "default": "pending"
          },
          "importId": {
            "type": "string",
            "title": "Importid"
          }
        },
        "type": "object",
        "required": [
          "groupId",
          "groupName",
          "moleculeIds",
          "moleculeCount",
          "importId"
        ],
        "title": "PublicUploadResponse"
      },
      "PublicUploadSession": {
        "properties": {
          "uploadId": {
            "type": "string",
            "title": "Uploadid"
          },
          "uploadUrl": {
            "type": "string",
            "title": "Uploadurl"
          },
          "uploadMethod": {
            "type": "string",
            "const": "PUT",
            "title": "Uploadmethod",
            "default": "PUT"
          },
          "uploadHeaders": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "title": "Uploadheaders"
          },
          "expiresIn": {
            "type": "integer",
            "title": "Expiresin"
          }
        },
        "type": "object",
        "required": [
          "uploadId",
          "uploadUrl",
          "expiresIn"
        ],
        "title": "PublicUploadSession"
      },
      "PublicValidateResponse": {
        "properties": {
          "valid": {
            "type": "boolean",
            "title": "Valid"
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/PublicDiagnostic"
            },
            "type": "array",
            "title": "Errors"
          }
        },
        "type": "object",
        "required": [
          "valid",
          "errors"
        ],
        "title": "PublicValidateResponse"
      },
      "PublicValidateTemplateRequest": {
        "properties": {
          "version": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "A version handle e.g. 'v1' to validate; absent -> default."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "PublicValidateTemplateRequest",
        "description": "Body for `POST /templates/{id}/validate` — validate the TEMPLATE ITSELF (no run bindings),\nagainst its own `metadata.defaultGroup` reference groups. `{}` is valid (validate the default\nversion)."
      },
      "PublicVersion": {
        "properties": {
          "status": {
            "$ref": "#/components/schemas/PublicVersionStatus"
          },
          "ref": {
            "type": "string",
            "title": "Ref"
          },
          "origin": {
            "$ref": "#/components/schemas/PublicVersionOrigin"
          },
          "versionName": {
            "type": "string",
            "title": "Versionname"
          },
          "buildStartedAt": {
            "type": "string",
            "title": "Buildstartedat"
          },
          "buildCompletedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Buildcompletedat"
          },
          "buildDurationSeconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Builddurationseconds"
          },
          "errorMessage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Errormessage"
          }
        },
        "type": "object",
        "required": [
          "status",
          "ref",
          "origin",
          "versionName",
          "buildStartedAt",
          "buildCompletedAt",
          "buildDurationSeconds",
          "errorMessage"
        ],
        "title": "PublicVersion"
      },
      "PublicVersionOrigin": {
        "type": "string",
        "enum": [
          "tamarind",
          "build",
          "save",
          "github",
          "rollback"
        ],
        "title": "PublicVersionOrigin"
      },
      "PublicVersionPage": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PublicVersion"
            },
            "type": "array",
            "title": "Items"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "PublicVersionPage"
      },
      "PublicVersionStatus": {
        "type": "string",
        "enum": [
          "Queued",
          "Running",
          "Complete",
          "Stopped"
        ],
        "title": "PublicVersionStatus"
      },
      "PublicVersionSummary": {
        "properties": {
          "version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Version",
            "description": "The version handle e.g. 'v1'."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat"
          },
          "isPublished": {
            "type": "boolean",
            "title": "Ispublished"
          },
          "isValid": {
            "type": "boolean",
            "title": "Isvalid"
          }
        },
        "type": "object",
        "required": [
          "version",
          "createdAt",
          "isPublished",
          "isValid"
        ],
        "title": "PublicVersionSummary"
      },
      "RunStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "finished",
          "partial",
          "stopped",
          "failed"
        ],
        "title": "RunStatus"
      },
      "Severity": {
        "type": "string",
        "enum": [
          "error",
          "warning"
        ],
        "title": "Severity"
      },
      "Source": {
        "type": "string",
        "enum": [
          "production",
          "test"
        ],
        "title": "Source"
      },
      "StepStatus": {
        "type": "string",
        "enum": [
          "waiting",
          "queued",
          "running",
          "finished",
          "failed",
          "skipped",
          "stopped",
          "cancelled"
        ],
        "title": "StepStatus"
      },
      "PublicProblem": {
        "description": "RFC 9457 problem detail. Serialized as `application/problem+json` on every public error.",
        "properties": {
          "type": {
            "description": "A URI identifying the error kind (dereferenceable docs).",
            "title": "Type",
            "type": "string"
          },
          "title": {
            "description": "A short, human-readable summary of the error kind.",
            "title": "Title",
            "type": "string"
          },
          "status": {
            "description": "The HTTP status code, duplicated in the body per RFC 9457.",
            "title": "Status",
            "type": "integer"
          },
          "code": {
            "description": "A stable machine-readable slug; switch on THIS, not prose.",
            "title": "Code",
            "type": "string"
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Instance-specific human explanation.",
            "title": "Detail"
          },
          "errors": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Structured per-item detail (request-validation fields OR pipeline diagnostics).",
            "title": "Errors"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "title": "PublicProblem",
        "type": "object"
      },
      "JobSubmission": {
        "type": "object",
        "required": [
          "jobName",
          "type",
          "settings"
        ],
        "properties": {
          "jobName": {
            "type": "string",
            "description": "Name for the job, unique within your account. Characters outside [A-Za-z0-9_.- ] are stripped and whitespace becomes underscores, so a name is sanitised rather than rejected.",
            "minLength": 1,
            "example": "my-protein-analysis"
          },
          "type": {
            "type": "string",
            "description": "Tool to run. The available tools are account-scoped — fetch the live list from `GET /tools` rather than assuming a name.",
            "example": "alphafold"
          },
          "settings": {
            "type": "object",
            "additionalProperties": true,
            "description": "Tool-specific settings. The accepted fields differ per tool and per account, so they are not enumerated here: fetch the JSON Schema for the tool you are submitting from `GET /tools/{name}/schema` and validate against that. `POST /validate-job` checks a payload for free.",
            "example": {
              "sequence": "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ"
            }
          }
        }
      },
      "BatchSubmission": {
        "type": "object",
        "required": [
          "batchName",
          "type",
          "settings"
        ],
        "properties": {
          "batchName": {
            "type": "string",
            "description": "Name for the batch, unique within your account. A batch name is held by a lock for 15 minutes after submission, so reusing one within that window returns 409. A batch name that is empty after normalization is rejected with 400.",
            "minLength": 1,
            "example": "my-batch-analysis"
          },
          "type": {
            "type": "string",
            "description": "Tool to run for every job in the batch.",
            "example": "alphafold"
          },
          "settings": {
            "type": "array",
            "description": "One settings object per job — the array form is what distinguishes this endpoint from `/submit-job`. See `JobSubmission.settings` for where the per-tool shape comes from.",
            "minItems": 1,
            "maxItems": 30000,
            "items": {
              "$ref": "#/components/schemas/JobSubmission/properties/settings"
            }
          },
          "jobNames": {
            "type": "array",
            "description": "Optional names, the same length as `settings`. Omit to have jobs auto-named. If any name collides with an existing job, every name is rewritten as `{batchName}-{name}`.\nNo stored name may equal the batch's own name. The batch is itself a job under that name, so the two would collide and the batch could never finish; such a submission is rejected with 400.",
            "minItems": 1,
            "maxItems": 30000,
            "items": {
              "$ref": "#/components/schemas/JobSubmission/properties/jobName"
            }
          }
        }
      },
      "JobResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Response message",
            "example": "Job submitted successfully"
          }
        }
      },
      "BatchResponse": {
        "type": "object",
        "properties": {
          "batchName": {
            "type": "string",
            "description": "Name of the submitted batch"
          },
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobResponse"
            }
          },
          "totalJobs": {
            "type": "integer",
            "description": "Total number of jobs in the batch"
          }
        }
      },
      "JobResult": {
        "type": "object",
        "properties": {
          "jobName": {
            "type": "string",
            "description": "Name of the job"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ],
            "description": "Current status of the job"
          },
          "results": {
            "type": "object",
            "description": "Job results (structure varies by tool)",
            "additionalProperties": true
          },
          "error": {
            "type": "string",
            "description": "Error message if job failed"
          },
          "outputFiles": {
            "type": "array",
            "description": "List of output files",
            "items": {
              "type": "object",
              "properties": {
                "fileName": {
                  "type": "string",
                  "description": "Name of the output file"
                },
                "fileUrl": {
                  "type": "string",
                  "description": "URL to download the file"
                },
                "fileType": {
                  "type": "string",
                  "description": "Type of the file (PDB, JSON, etc.)"
                }
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          },
          "detail": {
            "type": "string",
            "description": "Error message (V2 alias — same text as `error`, for FastAPI DomainException compatibility)"
          },
          "code": {
            "type": "string",
            "description": "Error code"
          },
          "details": {
            "type": "object",
            "description": "Additional error details"
          },
          "getApiKey": {
            "type": "string",
            "format": "uri",
            "description": "Present on a missing/invalid API-key rejection: the page where a key is created, on the host that served this response (a tenant deployment names its own host, because a key from the shared app does not work against a tenant pod). Agents arrive by calling and failing rather than by browsing, so the way out ships with the rejection."
          },
          "agentGuide": {
            "type": "string",
            "format": "uri",
            "description": "Present on a missing/invalid API-key rejection: the LLM-readable API guide."
          },
          "toolCatalog": {
            "type": "string",
            "format": "uri",
            "description": "Present on a missing/invalid API-key rejection: the keyless tool catalog, so a correct payload can be built before a key exists."
          },
          "hint": {
            "type": "string",
            "description": "Present on a missing/invalid API-key rejection: plain-language next step. States that a key cannot be minted programmatically."
          }
        }
      },
      "PublicToolInfo": {
        "type": "object",
        "description": "One tool in the keyless catalogue (`/tools-catalog`). Note the field names differ from `ToolInfo` on purpose: the wire value is `type` here, matching the key you actually send to `/submit-job`, while the human label is `displayName`. (`ToolInfo` calls the same wire value `name`.) A display name is never a valid `type`.",
        "properties": {
          "type": {
            "type": "string",
            "description": "The exact, case-sensitive value to send as `type` when submitting.",
            "example": "alphafold"
          },
          "displayName": {
            "type": "string",
            "description": "Human label for the tool. NOT a valid `type` value.",
            "example": "AlphaFold"
          },
          "description": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "description": "Intent tags, usable as the `tag` query parameter.",
            "items": {
              "type": "string"
            },
            "example": [
              "structure-prediction"
            ]
          },
          "taskSetting": {
            "type": "string",
            "description": "The setting whose value the `tasks` predicates below refer to. Present only for multi-task tools. Do NOT assume it is called `task`: it is `metricType` on `protein-metrics`, `binderType` on `boltzgen` and `inputFormat` on `boltz`, `chai` and `esmfold2`, among 55 tools that name it something else. Sending the wrong key produces no error — unrecognised settings keys are flagged, not rejected — just the wrong set of required fields.",
            "example": "metricType"
          },
          "requiredSettings": {
            "type": "array",
            "description": "The tool's REQUIRED settings only — enough to build a valid payload without a key. Optional parameters, defaults and descriptions need `/tools/{name}/schema`. Send these names verbatim: an unrecognised key is flagged, not rejected, so a typo shows up only as the real field reading as missing.\n\nRequiredness is usually CONDITIONAL, so read `tasks` and `conditionals` before treating this as a checklist: most multi-task tools list alternative branches, not fields that are all needed at once. `proto`, for example, requires `task` plus exactly ONE of the remaining entries, and `rfdiffusion3` lists `jsonFile` and `jsonConfig`, which are mutually exclusive.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Send this exact key inside `settings`."
                },
                "required": {
                  "type": "boolean",
                  "description": "Present and `false` on entries you need NOT send. They appear in this list only because another entry's `tasks` or `conditionals` names them, and a predicate whose controller is missing from the document cannot be acted on. Read their `default` — it is what silently selects a branch: `pysca.useMSA` defaults to true, so a payload sending only `fastaFile` takes the other branch and is rejected for a missing `sequence`. Omitted entirely (not set to `true`) on genuinely required entries."
                },
                "type": {
                  "type": "string",
                  "description": "The field's input type, e.g. `string`, `number`, `file`."
                },
                "list": {
                  "type": "boolean",
                  "description": "When true, send an ARRAY of `type`, not a single value. Omitted when false."
                },
                "lowerBound": {
                  "type": "number",
                  "description": "Enforced minimum. A smaller value is rejected."
                },
                "upperBound": {
                  "type": "number",
                  "description": "Enforced maximum. A larger value is rejected."
                },
                "maxLength": {
                  "type": "integer",
                  "description": "Maximum sequence length in residues (whitespace is not counted). Exceeding it is a 400. Published only where the validator actually applies the cap — a non-list field that is a `sequence` type or is literally named `sequence`. Limits range from 14 residues to 20,000, so check before sending a long chain."
                },
                "maxLengthNote": {
                  "type": "string",
                  "description": "Why the cap exists, where the tool explains it — usually \"this tool folds only the antibody variable domain (Fv)\". Read it before truncating to fit."
                },
                "sep": {
                  "type": "string",
                  "description": "The literal delimiter for a residue-selection field, published when the field ships no `example`. `\" \"` means space-separated (`\"1 2 3\"`); `\",\"` means comma-separated ranges (`\"1-5,7,9-11\"`). This matters more than it looks: the wrong form is NOT rejected, it is read as different residues, so the job silently runs on the wrong positions."
                },
                "contigsFormat": {
                  "type": "string",
                  "description": "Names the form a residue-selection field expects (e.g. `ranges`). Published alongside `sep` where the tool defines it."
                },
                "unknownResidue": {
                  "type": "string",
                  "enum": [
                    "X-stripped"
                  ],
                  "description": "Present on protein sequence fields only. `X` is NOT covered by `alphabet` and is NOT rejected: the validator accepts it and normalization REMOVES it before the job runs, which shifts every residue index after it. Absent on nucleotide fields, where `X` really is a 400."
                },
                "alphabet": {
                  "type": "string",
                  "description": "The accepted residue characters. An out-of-alphabet character is rejected with a 400 naming this same set — except `X` on a field carrying `unknownResidue`, which is accepted and stripped. Do NOT assume `type: \"sequence\"` means protein: `disco.dnaSequence` accepts `ATGCN` and `rna-fm.sequence` accepts `ACGU`, so a protein chain sent to either is refused. Whitespace is tolerated and may appear in the published set."
                },
                "defaultByTask": {
                  "description": "A per-task LOOKUP, not a value to send: read your branch out of it. Present instead of `default` when the tool's default varies by the task selector — publishing `{\"antibody\": [...], \"nanobody\": [...]}` as `default` would invite a consumer to submit the map where an array is expected. A map covering every selector option is autofilled whatever branch you pick, so those fields are not listed as required at all."
                },
                "singleChain": {
                  "type": "boolean",
                  "description": "Present and true when a colon-separated complex is REJECTED on this field. `:` is how every other sequence field in this API expresses a multi-chain input, so this is not inferable from `type: \"sequence\"`."
                },
                "minChains": {
                  "type": "integer",
                  "description": "Minimum colon-separated chains. Enforced before ordinary field validation, so a payload below it fails early."
                },
                "maxChains": {
                  "type": "integer",
                  "description": "Maximum colon-separated chains."
                },
                "subfields": {
                  "type": "array",
                  "description": "Present when each item is an OBJECT rather than a scalar — `type` and `list` alone cannot express that, and submitting a bare string is rejected. Each entry gives an item key, and its `options` where the key is an enum. Read those per tool instead of assuming a shared set: `chai` accepts a `glycan` molecule type, `boltz` does not, and `rf3` takes only `protein` and `ligand`.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "options": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "list": {
                        "type": "boolean"
                      },
                      "required": {
                        "type": "boolean"
                      }
                    }
                  }
                },
                "example": {
                  "description": "One filled-in value, published only for settings that carry `subfields` — where the nesting is the hard part. Not published for ordinary scalar settings, whose `type` already says what to send."
                },
                "default": {
                  "description": "The value that applies if you omit this setting. Present only where it is load-bearing — a task selector, or a field another entry's `conditionals` depend on. Omitting `rfdiffusion3.jsonInputType`, for instance, silently applies `file`, which is what decides whether `jsonFile` or `jsonConfig` becomes required."
                },
                "options": {
                  "type": "array",
                  "description": "When present, the value must be one of these.",
                  "items": {
                    "type": "string"
                  }
                },
                "extension": {
                  "type": "array",
                  "description": "For file fields, the EFFECTIVE accepted extensions — what submission actually takes, not the registry's raw list. Any list containing `pdb` is widened with `cif`, because the validator accepts a CIF for a PDB field and converts it before dispatch. Fields that opt out of that conversion keep their raw list.",
                  "items": {
                    "type": "string"
                  }
                },
                "tasks": {
                  "type": "array",
                  "description": "When present, this setting is required ONLY if the tool's task selector holds one of these values. The selector is named by the entry's `taskSetting` — it is not always `task`. Absent means unconditionally required.",
                  "items": {
                    "type": "string"
                  }
                },
                "conditionals": {
                  "type": "array",
                  "description": "When present, this setting is required ONLY while another setting holds a given value — the mechanism behind mutually exclusive inputs.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "otherSettingName": {
                        "type": "string",
                        "description": "The setting this one depends on."
                      },
                      "otherSettingValue": {
                        "description": "The value that makes this setting required."
                      },
                      "checkType": {
                        "type": "string",
                        "description": "How the values are compared, e.g. `equals`."
                      }
                    }
                  }
                }
              },
              "required": [
                "name"
              ]
            }
          }
        },
        "required": [
          "type"
        ]
      },
      "ToolInfo": {
        "type": "object",
        "description": "One tool in the catalogue. `settings` describes its parameters; fetch `GET /tools/{name}/schema` for the same information as JSON Schema.\n\n`taskType` is the tool's pipeline task category (`structure-prediction`, `inverse-folding`, `score`, …) — the fact pipelines chain on. Two tools connect when the molecule type one produces matches what the next consumes (a `pdb` output may also feed a `sequence` input, since sequences are read from structures).",
        "properties": {
          "name": {
            "type": "string",
            "description": "The value to send as `type` when submitting.",
            "example": "alphafold"
          },
          "displayName": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "github": {
            "type": "string"
          },
          "paper": {
            "type": "string"
          },
          "settings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "required": {
                  "type": "boolean"
                },
                "type": {
                  "type": "string",
                  "description": "Present only for a subset of parameter kinds — read it defensively, and prefer the JSON Schema from `/tools/{name}/schema`."
                },
                "description": {
                  "type": "string"
                },
                "options": {
                  "type": "array",
                  "items": {}
                },
                "default": {},
                "extension": {
                  "type": "array",
                  "description": "For a file parameter, the file formats it accepts — the only published statement of what this tool's parser can read.",
                  "items": {
                    "type": "string"
                  },
                  "example": [
                    "pdb",
                    "cif"
                  ]
                },
                "list": {
                  "type": "boolean",
                  "description": "True when this parameter takes an ARRAY of the stated `type` rather than a single value."
                }
              }
            }
          },
          "outputTypes": {
            "type": "array",
            "description": "What the tool declares it produces — molecular (`pdb`, `sequence`, `sdf`, `smiles`) alongside file and score types (`csv`, `score`, `cif`, …). A few tools use compound values such as `pdb-list`, so match by containment rather than equality.\n\nThis describes the ARTIFACTS a run leaves behind. To chain stages, match on `taskType` and the molecule types: a scoring stage passes its input type through even though its `outputTypes` says `score`. Absent means the tool declares nothing, which is unknown rather than \"produces nothing\"; and a type here is not proof the tool generated it, since a scoring tool can echo its input.",
            "items": {
              "type": "string"
            },
            "example": [
              "pdb"
            ]
          },
          "taskType": {
            "type": "string",
            "description": "The tool's pipeline task category (`structure-prediction`, `inverse-folding`, `score`, …) — the fact pipelines chain on. Absent for a tool that declares none.",
            "example": "structure-prediction"
          },
          "filterMetrics": {
            "type": "array",
            "description": "Metric names accepted in a pipeline stage's filter settings. Deliberately narrower than `outputs.columns` — `/submit-pipeline` rejects a filter on a column that is not filterable. Absent for tools whose filters are not validated.",
            "items": {
              "type": "string"
            }
          },
          "outputs": {
            "type": "object",
            "description": "The tool's result table, when it declares one. (The tool's `taskType` is a TOP-LEVEL field, not nested here.)",
            "properties": {
              "produces": {
                "type": "array",
                "description": "Molecular representations the output carries — as a column of the result table OR as a file written alongside it — INCLUDING any carried over from the input, so a scoring tool can list one here.",
                "items": {
                  "type": "string"
                }
              },
              "mainCSV": {
                "type": "string",
                "description": "Filename of the primary results CSV."
              },
              "byTask": {
                "type": "object",
                "description": "For a tool whose output depends on the task it runs: the per-task contract, keyed by task value, and authoritative for the task you set. Each entry is COMPLETE — a task that does not redeclare `mainCSV` or `taskType` inherits the tool's top-level value (the top-level `taskType` field and this block's `mainCSV`).\n\nThe top-level `taskType` and this block's `mainCSV`/`produces` summarize ACROSS tasks — `produces` is the union over every task's table, and `taskType`/`mainCSV` are the tool's top-level declaration, which is not guaranteed to be the task selector's default. Do not read them as describing the run you are about to submit.",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "taskType": {
                      "type": "string"
                    },
                    "mainCSV": {
                      "type": "string"
                    },
                    "generates": {
                      "type": "array",
                      "description": "What this task creates FRESH — distinct from the sibling `produces`, which is what the result table contains. Empty for a scoring task, whose table may still echo its input.",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "byTaskNote": {
                "type": "string",
                "description": "Present alongside `byTask`: restates in prose how to read the per-task contract against the across-task scalars."
              },
              "columns": {
                "type": "array",
                "description": "Columns of the main CSV. To FILTER on one in a pipeline, check `filterMetrics` — not every column is filterable.",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Column name as it appears in the CSV."
                    },
                    "type": {
                      "type": "string",
                      "description": "Column type: pdb, sequence, number, string, …"
                    },
                    "displayName": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "units": {
                      "type": "string"
                    },
                    "scoringPropertyName": {
                      "type": "string",
                      "description": "Name this metric is stored under when results are ingested, for tools that expose the column as a scoring property."
                    },
                    "recommendedRange": {
                      "type": "array",
                      "description": "Advisory [min, max] for a good value; either end may be an empty string when unbounded on that side.",
                      "items": {}
                    },
                    "lowIsGood": {
                      "type": "boolean",
                      "description": "Present and true when a LOWER value is better (RMSD, PAE, energy) — the direction to rank in."
                    },
                    "tasks": {
                      "type": "array",
                      "description": "Present only on a task-gated tool: the tasks whose results include this column. An UNTAGGED column is simply not task-gated in the tool's declaration, which does not promise every task fills it.",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ValidationResult": {
        "type": "object",
        "required": [
          "valid"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "normalized": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present when valid — the settings to submit, with defaults filled in."
          },
          "job_name": {
            "type": "string",
            "description": "The name the job would actually be STORED under, present whenever you sent a `jobName`. Submission strips everything outside `[A-Za-z0-9_\\s.-]` and turns whitespace into `_`, so \"PD-L1 binder #3\" is stored as \"PD-L1_binder_3\". Key every later lookup (`/jobs`, `/result`, `/job-logs`) on THIS value — the original name answers \"not found\"."
          },
          "job_name_changed": {
            "type": "boolean",
            "description": "Present and true only when `job_name` differs from the `jobName` you sent."
          },
          "error": {
            "type": "string",
            "description": "Present when invalid — the first problem found."
          },
          "missing_fields": {
            "type": "array",
            "description": "Best-effort list of required inputs still missing. May be empty even when `valid` is false, because validation stops at the first error.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "displayName": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "example": {}
              }
            }
          }
        }
      },
      "PipelineStage": {
        "type": "object",
        "required": [
          "task",
          "toolSettings"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Ignored on submit. The server assigns each stage a 1-based index and uses that in error messages, overwriting anything sent here."
          },
          "task": {
            "type": "string",
            "description": "What this stage does, e.g. \"Structure Prediction\"."
          },
          "tools": {
            "type": "array",
            "description": "Optional and derived — submission overwrites it with the keys of `toolSettings` (submit-pipeline.js), so an empty array is accepted. It only widens the set checked against your account's tool access, so naming a tool here without settings for it grants nothing.",
            "items": {
              "type": "string"
            }
          },
          "toolSettings": {
            "type": "object",
            "additionalProperties": true,
            "minProperties": 1,
            "description": "Settings per tool, keyed by tool name — this is what determines which tools the stage runs, so it may not be empty. Each value follows that tool's schema from `GET /tools/{name}/schema`."
          },
          "scoringTools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scoringToolSettings": {
            "type": "object",
            "additionalProperties": true
          },
          "filterSettings": {
            "type": "object",
            "additionalProperties": true,
            "description": "Metric filters applied to this stage's outputs. Metric names are case-sensitive and tool-specific; an unknown one is rejected with the valid options listed."
          }
        }
      },
      "DeployedModel": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Use this as the `type` when submitting a job."
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "created": {
            "type": "string"
          },
          "gpu": {
            "type": "boolean"
          },
          "environment": {
            "type": "string"
          },
          "entrypoint": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "testUrl": {
            "type": "string",
            "description": "Present on deploy — a page for trying the model."
          },
          "email": {
            "type": "string",
            "description": "Present only when the model belongs to another member of your organization."
          }
        }
      },
      "FinetunedModel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Use this as the `modelName` when submitting."
          },
          "type": {
            "type": "string"
          },
          "inferenceType": {
            "type": [
              "string",
              "null"
            ]
          },
          "baseModel": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "created": {
            "type": "string"
          },
          "owner": {
            "type": "string",
            "description": "Present only when the model belongs to another member of your organization."
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is valid HTTP but uses an unsupported parameter combination.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "API key missing or invalid.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The authenticated API key is not allowed to use this operation.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "NotFound": {
        "description": "The addressed resource does not exist, or is not visible to your tenant.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "A dependency required by this operation is temporarily unavailable.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "ValidationProblem": {
        "description": "The request was malformed or failed validation; see `errors` for the offending fields.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      },
      "Error": {
        "description": "An error occurred (RFC 9457 problem+json). Switch on the stable `code`, not on prose.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/PublicProblem"
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Jobs",
      "description": "Job submission and management"
    },
    {
      "name": "Tools",
      "description": "The tool catalogue"
    },
    {
      "name": "Files",
      "description": "File upload and management"
    },
    {
      "name": "Results",
      "description": "Job results retrieval"
    },
    {
      "name": "Models",
      "description": "Finetuned models"
    },
    {
      "name": "Usage",
      "description": "Usage statistics"
    },
    {
      "name": "Pipelines",
      "description": "Legacy saved pipelines"
    }
  ]
}