openapi: 3.1.0 info: title: RAGCore API version: 1.2.1 description: Central secure local-first retrieval platform contract. servers: - url: https://ragcore.example.test security: - bearerAuth: [] tags: - name: health - name: control - name: ingestion - name: retrieval - name: operations paths: /health/live: get: security: [] tags: [health] operationId: getLiveness responses: '200': description: Process is alive. content: application/json: schema: {$ref: '#/components/schemas/Health'} /health/ready: get: security: [] tags: [health] operationId: getReadiness responses: '200': description: Required dependencies are ready. content: application/json: schema: {$ref: '#/components/schemas/Readiness'} '503': {$ref: '#/components/responses/Problem'} /v1/applications: get: tags: [control] operationId: listApplications parameters: - {$ref: '#/components/parameters/Cursor'} - {$ref: '#/components/parameters/Limit'} responses: '200': description: Applications visible to the caller. content: application/json: schema: $ref: '#/components/schemas/ApplicationPage' '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} post: tags: [control] operationId: createApplication parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ApplicationCreate'} responses: '201': description: Application created. content: application/json: schema: {$ref: '#/components/schemas/Application'} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '409': {$ref: '#/components/responses/Problem'} /v1/applications/{application_id}/credentials: post: tags: [control] operationId: issueApplicationCredential parameters: - {$ref: '#/components/parameters/ApplicationId'} - {$ref: '#/components/parameters/IdempotencyKey'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CredentialIssueRequest'} responses: '201': description: Credential issued; plaintext token is returned only here. content: application/json: schema: {$ref: '#/components/schemas/CredentialIssued'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/knowledge-spaces: get: tags: [control] operationId: listKnowledgeSpaces parameters: - {$ref: '#/components/parameters/Cursor'} - {$ref: '#/components/parameters/Limit'} responses: '200': description: Authorized spaces. content: application/json: schema: {$ref: '#/components/schemas/KnowledgeSpacePage'} post: tags: [control] operationId: createKnowledgeSpace parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/KnowledgeSpaceCreate'} responses: '201': description: Knowledge space created. content: application/json: schema: {$ref: '#/components/schemas/KnowledgeSpace'} '403': {$ref: '#/components/responses/Problem'} '409': {$ref: '#/components/responses/Problem'} /v1/knowledge-spaces/{space_id}/grants: post: tags: [control] operationId: createSpaceGrant parameters: - {$ref: '#/components/parameters/SpaceId'} - {$ref: '#/components/parameters/IdempotencyKey'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/SpaceGrantCreate'} responses: '201': description: Grant created. content: application/json: schema: {$ref: '#/components/schemas/SpaceGrant'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/policies: get: tags: [control] operationId: listPolicies parameters: - {$ref: '#/components/parameters/Cursor'} - {$ref: '#/components/parameters/Limit'} responses: '200': description: Workspace policies visible to the caller. content: application/json: schema: {$ref: '#/components/schemas/PolicyPage'} '403': {$ref: '#/components/responses/Problem'} post: tags: [control] operationId: createPolicy parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/PolicyCreate'} responses: '201': description: Policy created. content: application/json: schema: {$ref: '#/components/schemas/Policy'} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} '409': {$ref: '#/components/responses/Problem'} /v1/uploads: post: tags: [ingestion] operationId: createUpload parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: multipart/form-data: schema: type: object required: [space_id, file] properties: space_id: {type: string, format: uuid} source_id: {type: [string, 'null'], format: uuid} external_id: {type: [string, 'null'], maxLength: 512, description: 'The stable id of this item at its source (e.g. a wiki page id). Requires source_id -- without one there is nothing stable to deduplicate against. Ingesting the same (source_id, external_id) pair again creates a new version of the same document instead of a duplicate.'} locale: {type: [string, 'null'], maxLength: 35, description: 'BCP-47-ish language tag for the content; defaults to en.'} file: {type: string, format: binary} responses: '202': description: Upload accepted and ingestion job created. content: application/json: schema: {$ref: '#/components/schemas/AcceptedJob'} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '413': {$ref: '#/components/responses/Problem'} '415': {$ref: '#/components/responses/Problem'} /v1/sources: get: tags: [ingestion] operationId: listSources parameters: - {$ref: '#/components/parameters/Cursor'} - {$ref: '#/components/parameters/Limit'} - name: space_id in: query schema: {type: string, format: uuid} responses: '200': description: Authorized sources. content: application/json: schema: {$ref: '#/components/schemas/SourcePage'} post: tags: [ingestion] operationId: createSource parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/SourceCreate'} responses: '201': description: Source created. content: application/json: schema: {$ref: '#/components/schemas/Source'} '403': {$ref: '#/components/responses/Problem'} /v1/sources/{source_id}/syncs: post: tags: [ingestion] operationId: startSourceSync parameters: - {$ref: '#/components/parameters/SourceId'} - {$ref: '#/components/parameters/IdempotencyKey'} responses: '202': description: Synchronization scheduled. content: application/json: schema: {$ref: '#/components/schemas/AcceptedJob'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/documents: get: tags: [ingestion] operationId: listDocuments description: >- Looks a document up by the sync client's own identity -- the primitive a client uses to decide skip-vs-update by comparing content_sha256 / source_fingerprint before ever uploading. With both filters: zero or one item; an unmatched filter is an empty page, not a 404. With only source_id: EVERY document that sync identity owns in the workspace (active and retired, each with its searchable version when it has one) -- the authoritative current set a sync client diffs its expected set against instead of trusting its own memory. Bounded (a sync source is a bounded set by construction), not paginated; no space_id/status browse mode. parameters: - name: source_id in: query required: true schema: {type: string, format: uuid} - name: external_id in: query required: false schema: {type: string, maxLength: 512} responses: '200': description: Zero or one matching document (with external_id), or every document of the source identity (without). content: application/json: schema: {$ref: '#/components/schemas/DocumentPage'} '400': {$ref: '#/components/responses/Problem'} '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} /v1/documents/{document_id}: get: tags: [ingestion] operationId: getDocument parameters: [{$ref: '#/components/parameters/DocumentId'}] responses: '200': description: Document with its active (published) version, if any. content: application/json: schema: {$ref: '#/components/schemas/Document'} '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/documents/{document_id}/versions: get: tags: [ingestion] operationId: listDocumentVersions description: Every version of the document regardless of state, newest first. Not paginated. parameters: [{$ref: '#/components/parameters/DocumentId'}] responses: '200': description: Every version of this document. content: application/json: schema: {$ref: '#/components/schemas/DocumentVersionPage'} '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/documents/{document_id}/retire: post: tags: [ingestion] operationId: retireDocument description: >- Soft-retires a document (source_deleted=true) via the existing mark_source_deleted; never a hard delete. Idempotent. Callers should only call this after a complete, successful source scan confirms the item is genuinely gone -- a partial or failed scan must not retire anything, per the reconcile rule in docs/04_INGESTION/CONNECTORS.md. Not enforced server-side: there is no concept of "a scan" on this side of the API. parameters: [{$ref: '#/components/parameters/DocumentId'}] responses: '200': description: The now-retired document. content: application/json: schema: {$ref: '#/components/schemas/Document'} '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/spaces/{space_id}/index/reconcile: post: tags: [ingestion] operationId: reconcileSpaceIndex description: >- Brings the searchable index of ONE knowledge space in line with its published, non-retired document versions: points that belong to a superseded version or to a retired (source_deleted) document are removed; nothing is re-embedded or inserted. Idempotent; scoped to the given space only (other spaces in the same collection are never read or written). The natural last step of a sync client's run after it has uploaded new versions and retired vanished items. parameters: - name: space_id in: path required: true schema: {type: string, format: uuid} responses: '200': description: Reconciliation outcome (counts). content: application/json: schema: {$ref: '#/components/schemas/SpaceIndexReconciliation'} '401': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} '503': {$ref: '#/components/responses/Problem'} /v1/jobs/{job_id}: get: tags: [operations] operationId: getJob parameters: [{$ref: '#/components/parameters/JobId'}] responses: '200': description: Job status. content: application/json: schema: {$ref: '#/components/schemas/Job'} '401': {$ref: '#/components/responses/Problem'} '404': {$ref: '#/components/responses/Problem'} /v1/search: post: tags: [retrieval] operationId: searchKnowledge requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/SearchRequest'} responses: '200': description: Authorized retrieval results. content: application/json: schema: {$ref: '#/components/schemas/SearchResponse'} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '503': {$ref: '#/components/responses/Problem'} '422': {$ref: '#/components/responses/Problem'} /v1/context: post: tags: [retrieval] operationId: buildContext requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ContextRequest'} responses: '200': description: Token-bounded context package. content: application/json: schema: {$ref: '#/components/schemas/ContextResponse'} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '422': {$ref: '#/components/responses/Problem'} '503': {$ref: '#/components/responses/Problem'} /v1/answers: post: tags: [retrieval] operationId: createAnswer requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AnswerRequest'} responses: '200': description: Grounded answer or explicit non-answer. content: application/json: schema: {$ref: '#/components/schemas/AnswerResponse'} text/event-stream: schema: {type: string} '400': {$ref: '#/components/responses/Problem'} '403': {$ref: '#/components/responses/Problem'} '422': {$ref: '#/components/responses/Problem'} '429': {$ref: '#/components/responses/Problem'} '503': {$ref: '#/components/responses/Problem'} /v1/citations/{citation_id}: get: tags: [retrieval] operationId: getCitation parameters: [{$ref: '#/components/parameters/CitationId'}] responses: '200': description: Authorized immutable citation. content: application/json: schema: {$ref: '#/components/schemas/Citation'} '404': {$ref: '#/components/responses/Problem'} /v1/feedback: post: tags: [retrieval] operationId: createFeedback parameters: [{$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/FeedbackCreate'} responses: '201': description: Feedback recorded. content: application/json: schema: {$ref: '#/components/schemas/Feedback'} '404': {$ref: '#/components/responses/Problem'} components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: RAGCore service token or OIDC session token parameters: Cursor: name: cursor in: query schema: {type: string, maxLength: 2048} Limit: name: limit in: query schema: {type: integer, minimum: 1, maximum: 100, default: 50} IdempotencyKey: name: Idempotency-Key in: header required: true schema: {type: string, minLength: 16, maxLength: 128} ApplicationId: {name: application_id, in: path, required: true, schema: {type: string, format: uuid}} SpaceId: {name: space_id, in: path, required: true, schema: {type: string, format: uuid}} SourceId: {name: source_id, in: path, required: true, schema: {type: string, format: uuid}} DocumentId: {name: document_id, in: path, required: true, schema: {type: string, format: uuid}} JobId: {name: job_id, in: path, required: true, schema: {type: string, format: uuid}} CitationId: {name: citation_id, in: path, required: true, schema: {type: string, format: uuid}} responses: Problem: description: Stable problem-details response. content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} schemas: SpaceIndexReconciliation: type: object required: [space_id, documents_total, documents_retired, searchable_versions, points_before, deleted_points, orphaned_documents, points_after] properties: space_id: {type: string, format: uuid} documents_total: {type: integer} documents_retired: {type: integer} searchable_versions: {type: integer} points_before: {type: integer} deleted_points: {type: integer} orphaned_documents: {type: integer} points_after: {type: integer} Health: type: object required: [status, service] properties: status: {const: ok} service: {const: ragcore} Readiness: type: object required: [status, components] properties: status: {enum: [ok, degraded, unavailable]} components: type: object additionalProperties: type: object required: [status] properties: status: {enum: [ok, unavailable]} latency_ms: {type: [number, 'null'], minimum: 0} code: {type: [string, 'null']} Problem: type: object required: [type, title, status, code, trace_id] properties: type: {type: string, format: uri} title: {type: string} status: {type: integer, minimum: 400, maximum: 599} code: {type: string, pattern: '^[A-Z0-9_]+$'} detail: {type: [string, 'null']} trace_id: {type: string} retry_after_seconds: {type: [integer, 'null'], minimum: 0} errors: {type: array, items: {type: object}} ApplicationCreate: type: object additionalProperties: false required: [slug, display_name] properties: slug: {type: string, pattern: '^[a-z0-9][a-z0-9.-]{1,62}$'} display_name: {type: string, minLength: 1, maxLength: 120} description: {type: [string, 'null'], maxLength: 1000} scopes: {type: array, uniqueItems: true, items: {$ref: '#/components/schemas/ApplicationScope'}} default_space_ids: {type: array, uniqueItems: true, items: {type: string, format: uuid}} Application: allOf: - {$ref: '#/components/schemas/ApplicationCreate'} - type: object required: [id, workspace_id, status, created_at] properties: id: {type: string, format: uuid} workspace_id: {type: string, format: uuid} status: {enum: [active, disabled]} created_at: {type: string, format: date-time} ApplicationPage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/Application'}} next_cursor: {type: [string, 'null']} CredentialIssueRequest: type: object additionalProperties: false required: [name, scopes] properties: name: {type: string, minLength: 1, maxLength: 120} scopes: {type: array, uniqueItems: true, items: {type: string}} expires_at: {type: [string, 'null'], format: date-time} CredentialIssued: type: object required: [id, token, token_prefix, scopes, created_at] properties: id: {type: string, format: uuid} token: {type: string, writeOnly: true} token_prefix: {type: string} scopes: {type: array, items: {type: string}} created_at: {type: string, format: date-time} expires_at: {type: [string, 'null'], format: date-time} ApplicationScope: enum: [search, context, answer, documents:read, citations:read, feedback:write, sources:sync] PolicyCreate: type: object additionalProperties: false required: [operation] properties: operation: {type: string, minLength: 1, maxLength: 120} knowledge_space_id: {type: [string, 'null'], format: uuid} required_scopes: {type: array, uniqueItems: true, items: {$ref: '#/components/schemas/ApplicationScope'}} Policy: allOf: - {$ref: '#/components/schemas/PolicyCreate'} - type: object required: [id, workspace_id, active, created_at] properties: id: {type: string, format: uuid} workspace_id: {type: string, format: uuid} active: {type: boolean} created_at: {type: string, format: date-time} PolicyPage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/Policy'}} next_cursor: {type: [string, 'null']} DataPolicy: enum: [local_only, local_preferred, cloud_allowed, retrieval_only, no_generation] KnowledgeSpaceCreate: type: object additionalProperties: false required: [slug, display_name, data_policy] properties: slug: {type: string, pattern: '^[a-z0-9][a-z0-9._-]{1,100}$'} display_name: {type: string, minLength: 1, maxLength: 120} description: {type: [string, 'null'], maxLength: 2000} data_policy: {$ref: '#/components/schemas/DataPolicy'} minimum_trust: {enum: [trusted_internal, trusted_external, unverified, user_uploaded, internet]} retention_days: {type: integer, minimum: 1, maximum: 3650, default: 90} KnowledgeSpace: allOf: - {$ref: '#/components/schemas/KnowledgeSpaceCreate'} - type: object required: [id, workspace_id, status, created_at] properties: id: {type: string, format: uuid} workspace_id: {type: string, format: uuid} status: {enum: [active, disabled]} created_at: {type: string, format: date-time} KnowledgeSpacePage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/KnowledgeSpace'}} next_cursor: {type: [string, 'null']} SpaceGrantCreate: type: object additionalProperties: false required: [principal_type, principal_id, permissions] properties: principal_type: {enum: [application, user, role]} principal_id: {type: string, format: uuid} permissions: {type: array, uniqueItems: true, items: {enum: [read, search, context, answer, manage_sources, manage_space]}} SpaceGrant: allOf: - {$ref: '#/components/schemas/SpaceGrantCreate'} - type: object required: [id, space_id, created_at] properties: id: {type: string, format: uuid} space_id: {type: string, format: uuid} created_at: {type: string, format: date-time} SourceType: {enum: [upload, folder, git, website]} SourceCreate: type: object additionalProperties: false required: [space_id, type, name, config] properties: space_id: {type: string, format: uuid} type: {$ref: '#/components/schemas/SourceType'} name: {type: string, minLength: 1, maxLength: 160} config: {type: object, description: Typed and redacted per connector; secrets use references.} enabled: {type: boolean, default: true} Source: allOf: - {$ref: '#/components/schemas/SourceCreate'} - type: object required: [id, status, created_at] properties: id: {type: string, format: uuid} status: {enum: [active, disabled, degraded]} last_sync_at: {type: [string, 'null'], format: date-time} created_at: {type: string, format: date-time} SourcePage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/Source'}} next_cursor: {type: [string, 'null']} DocumentVersionStatus: enum: [acquired, security_checked, parsed, normalized, chunked, embedded, indexed, validated, published, superseded, retired, failed] DocumentVersion: type: object required: [id, document_id, status, source_fingerprint, content_sha256] properties: id: {type: string, format: uuid} document_id: {type: string, format: uuid} status: {$ref: '#/components/schemas/DocumentVersionStatus'} source_fingerprint: {type: string} content_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} created_at: {type: [string, 'null'], format: date-time} DocumentVersionPage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/DocumentVersion'}} next_cursor: {type: [string, 'null']} Document: type: object required: [id, space_id, external_id, title, status] properties: id: {type: string, format: uuid} space_id: {type: string, format: uuid} source_id: {type: [string, 'null'], format: uuid, description: 'Null for a document ingested without a source_id (e.g. an ad hoc upload).'} external_id: {type: string} title: {type: string} status: {enum: [active, source_deleted]} active_version: {oneOf: [{$ref: '#/components/schemas/DocumentVersion'}, {type: 'null'}]} DocumentPage: type: object required: [items] properties: items: {type: array, items: {$ref: '#/components/schemas/Document'}} next_cursor: {type: [string, 'null']} JobStatus: {enum: [ready, leased, succeeded, retry_wait, terminal]} Job: type: object required: [id, operation, status, attempt_count, max_attempts] properties: id: {type: string, format: uuid} operation: {type: string} status: {$ref: '#/components/schemas/JobStatus'} attempt_count: {type: integer, minimum: 0} max_attempts: {type: integer, minimum: 1} last_error_code: {type: [string, 'null']} AcceptedJob: type: object required: [job_id, status_url] properties: job_id: {type: string, format: uuid} status_url: {type: string, format: uri-reference} SearchFilter: type: object additionalProperties: false properties: content_types: {type: array, uniqueItems: true, maxItems: 50, items: {type: string}} languages: {type: array, uniqueItems: true, maxItems: 50, items: {type: string, minLength: 2, maxLength: 16}} source_ids: {type: array, uniqueItems: true, maxItems: 50, items: {type: string, format: uuid}} document_ids: {type: array, uniqueItems: true, maxItems: 50, items: {type: string, format: uuid}} trust_levels: {type: array, uniqueItems: true, maxItems: 50, items: {enum: [trusted_internal, trusted_external, unverified, user_uploaded, internet]}} SearchRequest: type: object additionalProperties: false required: [query] properties: query: {type: string, minLength: 1, maxLength: 8000, pattern: '.*\S.*'} requested_space_ids: {type: array, uniqueItems: true, maxItems: 50, items: {type: string, format: uuid}} profile: {type: string, pattern: '^[a-z0-9][a-z0-9_-]{0,63}$', default: hybrid-v1} max_results: {type: integer, minimum: 1, maximum: 50, default: 10} filters: {$ref: '#/components/schemas/SearchFilter'} include_debug: {type: boolean, default: false, description: Authorized Query Lab use only.} Citation: type: object additionalProperties: false required: [id, document_id, document_version_id, title, excerpt, excerpt_sha256, source_uri] properties: id: {type: string, format: uuid} document_id: {type: string, format: uuid} document_version_id: {type: string, format: uuid} title: {type: string} section: {type: [string, 'null']} page_start: {type: [integer, 'null'], minimum: 1} page_end: {type: [integer, 'null'], minimum: 1} line_start: {type: [integer, 'null'], minimum: 1} line_end: {type: [integer, 'null'], minimum: 1} excerpt: {type: string} excerpt_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} source_uri: {type: string, description: 'Stable internal locator ragcore://source/.'} source_id: {type: [string, 'null'], format: uuid, description: 'Canonical source the cited document belongs to.'} source_name: {type: [string, 'null'], description: 'Registry name of the source (e.g. Uploads, Infra runbooks).'} source_kind: {type: [string, 'null'], enum: [upload, folder, git, website, null]} locator: {type: [string, 'null'], description: 'The item within the source (external id / path).'} revision: {type: [string, 'null'], description: 'Connector revision of the cited version (e.g. a Git commit).'} display: {type: string, description: 'Human-readable one-line provenance, e.g. "Network Design.pdf · p. 18 · Firewall Segmentation".'} CitationResponse: type: object additionalProperties: false required: [id, document_id, document_version_id, title, excerpt, excerpt_sha256, source_uri] properties: id: {type: string, format: uuid} document_id: {type: string, format: uuid} document_version_id: {type: string, format: uuid} title: {type: string} section: {type: [string, 'null']} page_start: {type: [integer, 'null'], minimum: 1} page_end: {type: [integer, 'null'], minimum: 1} line_start: {type: [integer, 'null'], minimum: 1} line_end: {type: [integer, 'null'], minimum: 1} excerpt: {type: string} excerpt_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} source_uri: {type: string, description: 'Stable internal locator ragcore://source/.'} source_id: {type: [string, 'null'], format: uuid, description: 'Canonical source the cited document belongs to.'} source_name: {type: [string, 'null'], description: 'Registry name of the source (e.g. Uploads, Infra runbooks).'} source_kind: {type: [string, 'null'], enum: [upload, folder, git, website, null]} locator: {type: [string, 'null'], description: 'The item within the source (external id / path).'} revision: {type: [string, 'null'], description: 'Connector revision of the cited version (e.g. a Git commit).'} display: {type: string, description: 'Human-readable one-line provenance, e.g. "Network Design.pdf · p. 18 · Firewall Segmentation".'} SearchResult: type: object required: [chunk_id, text, rank, citation] properties: chunk_id: {type: string, format: uuid} parent_chunk_id: {type: [string, 'null'], format: uuid} text: {type: string} rank: {type: integer, minimum: 1} scores: type: object properties: dense: {type: [number, 'null']} sparse: {type: [number, 'null']} fused: {type: [number, 'null']} rerank: {type: [number, 'null']} citation: {$ref: '#/components/schemas/Citation'} SearchResponse: type: object required: [retrieval_run_id, effective_space_ids, results, degraded] properties: retrieval_run_id: {type: string, format: uuid} effective_space_ids: {type: array, items: {type: string, format: uuid}} results: {type: array, items: {$ref: '#/components/schemas/SearchResult'}} degraded: {type: boolean} degradation_codes: {type: array, items: {type: string}} timings_ms: {type: object, additionalProperties: {type: number, minimum: 0}} ContextRequest: type: object additionalProperties: false required: [query] properties: query: {type: string, minLength: 1, maxLength: 8000, pattern: '.*\S.*'} requested_space_ids: {type: array, uniqueItems: true, maxItems: 50, items: {type: string, format: uuid}} profile: {type: string, pattern: '^[a-z0-9][a-z0-9_-]{0,63}$', default: hybrid-v1} max_results: {type: integer, minimum: 1, maximum: 50, default: 10} filters: {$ref: '#/components/schemas/SearchFilter'} include_debug: {type: boolean, default: false, description: Authorized Query Lab use only.} max_context_tokens: {type: integer, minimum: 256, maximum: 64000, default: 8000} ContextBlockResponse: type: object additionalProperties: false required: [text, citation_ids, token_count] properties: text: {type: string} citation_ids: {type: array, minItems: 1, items: {type: string, format: uuid}} token_count: {type: integer, minimum: 1} AnswerabilityStatus: {enum: [answerable, partially_answerable, not_answerable, conflicting_evidence]} ContextResponse: type: object additionalProperties: false required: [retrieval_run_id, answerability, token_count] properties: retrieval_run_id: {type: string, format: uuid} answerability: {$ref: '#/components/schemas/AnswerabilityStatus'} answerability_reasons: {type: array, items: {type: string}} blocks: {type: array, items: {$ref: '#/components/schemas/ContextBlockResponse'}} citations: {type: array, items: {$ref: '#/components/schemas/CitationResponse'}} token_count: {type: integer, minimum: 0} degraded: {type: boolean, default: false, description: 'True when retrieval fell back from its normal path (e.g. an unreachable reranker) but still produced these citations from a safe fallback ranking.'} degradation_reasons: {type: array, items: {type: string}} AnswerRequest: allOf: - {$ref: '#/components/schemas/ContextRequest'} - type: object properties: generation_profile: {type: string, default: answer-local-balanced-v1} stream: {type: boolean, default: false} AnswerClaim: type: object required: [text, citation_ids] properties: text: {type: string} citation_ids: {type: array, minItems: 1, items: {type: string, format: uuid}} AnswerResponse: type: object required: [answer_id, retrieval_run_id, answerability, answer, citations, claims] properties: answer_id: {type: string, format: uuid} retrieval_run_id: {type: string, format: uuid} answerability: {$ref: '#/components/schemas/AnswerabilityStatus'} answer: {type: string} claims: {type: array, items: {$ref: '#/components/schemas/AnswerClaim'}} citations: {type: array, items: {$ref: '#/components/schemas/Citation'}} degraded: {type: boolean, default: false, description: 'True on a generation retry or when retrieval degraded (e.g. an unreachable reranker fell back to fused ranking) -- the answer and citations are still real, not fabricated.'} degradation_reasons: {type: array, items: {type: string}} FeedbackCreate: type: object additionalProperties: false required: [target_type, target_id, rating] properties: target_type: {enum: [retrieval_run, answer]} target_id: {type: string, format: uuid} rating: {enum: [helpful, not_helpful, incorrect, incomplete, unsafe]} comment: {type: [string, 'null'], maxLength: 4000} Feedback: allOf: - {$ref: '#/components/schemas/FeedbackCreate'} - type: object required: [id, created_at] properties: id: {type: string, format: uuid} created_at: {type: string, format: date-time}