{"openapi":"3.1.0","info":{"title":"eli.ai Public API","version":"1.0.0","summary":"Grounded answers, the knowledge graph, and agent runs for one workspace.","description":"The machine-readable surface of an eli.ai workspace: grounded structured question answering,\ndocuments (list/read/create/update/delete) and hybrid search, the canonical entity catalog,\nknowledge-graph neighborhoods and manual graph editing, governed live-data connectors and named\nqueries, engagement reports, and agent runs (start, stream, inspect, cancel, approve, rate).\n\n## Authentication\n\nTwo kinds of bearer key are accepted, both minted in Settings and both carrying explicit scopes:\n\n- **Workspace keys** (`Authorization: Bearer eli_sk_...`) belong to one workspace and always act\n  on it. The workspace is resolved from the key — it never appears in the URL or payload.\n- **User keys** (`Authorization: Bearer eli_uk_...`) belong to a USER and may be granted one,\n  several, or all of that user's workspaces. When the grant names exactly one workspace, requests\n  need nothing extra; otherwise each request must name its target workspace with the\n  `X-Workspace-Id` header. The named workspace must be inside the key's grant, and the owner's\n  live workspace membership is re-checked on every request — leaving a workspace kills access\n  even for an explicitly granted workspace id.\n\nScopes (granular; a key may hold any subset):\n\n- `agents:run` — invoke models on the workspace's behalf (structured query, agent runs, cancel/approve/feedback).\n- `runs:read` — read agent runs and steps; also accepted on the graph reads (entities, neighborhoods) and the answer-policy reads (decisions, stats).\n- `kb:read` — read documents, full-text/vector search, the knowledge graph (entities, neighborhoods), and the answer-policy decision log and stats.\n- `kb:write` — create/edit/delete documents, entities, and relations.\n- `data:read` — list data connectors (credential-masked) and governed named queries.\n- `data:run` — execute governed named queries against connected data sources.\n- `reports:read` — list and read generated report snapshots.\n- `reports:write` — generate new report snapshots.\n\nExisting keys created before the granular scopes shipped default to `agents:run` + `runs:read` and keep working unchanged.\n\nA missing/invalid/revoked key yields `401 {\"error\":\"unauthorized\"}`; a valid key without the\noperation's scope yields `403 {\"error\":\"insufficient_scope\"}`. A multi-workspace user key that\nomits `X-Workspace-Id` yields `400 {\"error\":\"workspace_required\"}`; an `X-Workspace-Id` outside\nthe key's grant (or a lapsed membership) yields `403 {\"error\":\"workspace_forbidden\"}`.\n\n## MCP companion endpoint\n\nAgents that prefer tools over REST can speak MCP (Streamable HTTP) to `/api/mcp` using the same\n`Authorization: Bearer eli_sk_...` / `eli_uk_...` keys and the same `X-Workspace-Id` header\nsemantics. It is a non-REST companion to this API — the `eli_query`\ntool runs the same pipeline as `POST /api/v1/query` — and is therefore not described as a path here.\n\n## Rate limiting\n\nThere is no rate limiting on this API yet. `429` responses are not currently returned; treat your\nAPI key's scopes and your own client-side throttling as the only guard rails for now.\n\n## Errors\n\nErrors are small JSON envelopes: `{\"error\": \"<code-or-message>\"}`. Body-validation failures\n(400) additionally carry the Zod `issues[]` array. Operations that invoke a model return\n`409 {\"error\":\"no-model-configured\"}` when the workspace has no enabled chat model.","contact":{"name":"eli.ai","url":"https://eli.ai"}},"tags":[{"name":"Query","description":"One question in, a fully cited structured answer out."},{"name":"Documents","description":"The workspace document catalog: list, read, create, update, delete."},{"name":"Search","description":"Hybrid full-text + vector retrieval over the corpus."},{"name":"Entities","description":"The canonical entity catalog, graph neighborhoods, and manual entity editing."},{"name":"Relations","description":"Manual knowledge-graph edges between entities."},{"name":"Curation","description":"V2.0 governance: the workspace manifest, authority tiers and lifecycle, revision history, change requests, document verification, and the SKOS export."},{"name":"Lineage","description":"Per-document provenance + downstream impact + governance in one read: origin (connector/vault/upload source and sync history), the document.* audit trail, the concepts and relations the document produced, and the answers, cache entries, and entities that depend on it."},{"name":"Data","description":"Governed data connectors and named read-only queries."},{"name":"Reports","description":"Generated engagement/coverage report snapshots."},{"name":"Agent runs","description":"Start, stream, inspect, cancel, approve, and rate agent runs."},{"name":"Policy","description":"The V2.1 answer-policy engine: the append-only decision audit log and 30-day verdict statistics. Decisions are written by the chat/structured/agent pipelines; this API only reads them."},{"name":"Evals","description":"The V2.3 concept-anchored evaluation framework: per-run retrieval / RAGAS / abstention metrics, paired-significance run comparison, and graded-relevance (TREC qrel) authoring."},{"name":"Connectors","description":"V2.4 external ingestion sources (Confluence / SharePoint / Slack / markdown upload): credential-masked config CRUD and full/incremental sync triggers. Crawls run in the worker; this API configures and enqueues them."},{"name":"Cache","description":"The V2.4 semantic answer cache: read-only health statistics (mode, entry counts, hit rate). The cache is populated by the answer path and invalidated by document changes."},{"name":"Meta","description":"This specification."}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/openapi.json":{"get":{"operationId":"getOpenApiSpec","tags":["Meta"],"summary":"This OpenAPI 3.1 document","description":"Returns this specification with servers[] stamped to the serving origin. Public — no API key required. Cached for 5 minutes (`Cache-Control: public, max-age=300`).","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object","description":"An OpenAPI 3.1 document."}}}}}}},"/api/v1/query":{"post":{"operationId":"queryWorkspace","tags":["Query"],"summary":"Ask a grounded structured question","description":"Runs the structured query pipeline: retrieval over the workspace's documents, deterministic entity detection, optional governed live-data lookups (`includeData`), one chat-model generation, and a best-effort groundedness check. The response is a single JSON document with the answer, its atomic claims, the `[Sn]` source registry, the `[Dn]` data-call registry, the detected entities, usage, and the answer-policy verdict (`policy`). The V2.1 answer-policy engine wraps the pipeline: a pre-gate may short-circuit into a deterministic `clarify` or `abstain_with_pointers` answer (in `enforce` mode), and a post-gate attaches a calibrated confidence, caveats, and detected evidence conflicts — it never rewrites model prose. `policyMode` overrides the workspace's configured mode for this one call (explicit override wins; default is the workspace `policy.mode` setting — `shadow` computes and logs decisions without altering behavior, `off` skips gating entirely). Every gate decision is recorded in the policy decision log regardless of mode (unless `off`). Requires scope `agents:run` (the call invokes the workspace's chat model, and that scope is also what licenses the per-call policy override).","x-required-scope":"agents:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1,"maxLength":4000,"description":"The question to answer."},"includeData":{"type":"boolean","default":false,"description":"Also execute the data bindings of entities detected in the question (at most 3 governed read-only calls) and ground the answer in their rows as [Dn] citations."},"maxSources":{"type":"integer","minimum":1,"maximum":20,"description":"Cap on retrieved document chunks (default 8)."},"policyMode":{"type":"string","enum":["off","shadow","enforce"],"description":"Answer-policy mode override for this call. Omitted → the workspace's configured `policy.mode` applies. `enforce` lets the policy short-circuit (clarify/abstain) and attach verdicts; `shadow` computes and logs decisions without changing the answer; `off` skips policy gating entirely."}}},"example":{"question":"Is anything stuck on the Order Platform right now?","includeData":true}}}},"responses":{"200":{"description":"The structured, dual-cited answer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuredAnswer"},"example":{"answer":"The Order Platform currently reports 14 stuck orders in the fulfillment queue [D1]. Per the incident runbook, stuck orders older than 24 hours should be requeued from the fulfillment console [S1].","claims":[{"text":"The Order Platform currently reports 14 stuck orders in the fulfillment queue","citations":["D1"]},{"text":"Stuck orders older than 24 hours should be requeued from the fulfillment console","citations":["S1"]}],"sources":[{"id":"S1","docId":"01KY10AAAAAAAAAAAAAAAAAAAA","docTitle":"Order Platform incident runbook","docPath":"ops/order-platform-runbook.md","chunkId":"01KY10BBBBBBBBBBBBBBBBBBBB","snippet":"When orders remain in STUCK status for more than 24 hours, requeue them from the fulfillment console…"}],"dataCalls":[{"id":"D1","dataCallId":"01KY10CCCCCCCCCCCCCCCCCCCC","connectorName":"northwind-ops","queryTitle":"Stuck orders by age","rowCount":14,"executedAt":"2026-07-21T09:14:03.412Z"}],"entities":[{"id":"01KY0ZW3B8AVDR67NXSE96P81N","name":"Order Platform","type":"system","pagerank":0.0421}],"groundedness":{"verified":2,"total":2},"policy":{"mode":"enforce","verdict":"answer","confidence":0.82,"calibrationVersion":"bootstrap-v1","reasons":["confidence 0.82 >= answer floor 0.55"],"caveats":[],"conflicts":[]},"model":{"chat":"claude-sonnet-4-5","judge":"claude-haiku-4-5"},"usage":{"inputTokens":4210,"outputTokens":312,"costUsd":0.0173},"generatedAt":"2026-07-21T09:14:05.001Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/NoModelConfigured"}}}},"/api/v1/documents":{"get":{"operationId":"listDocuments","tags":["Documents"],"summary":"List documents","description":"Live documents in the workspace (tombstoned docs excluded), path order, paginated. Content is not included — read one document for its markdown. Requires scope `kb:read`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"limit","in":"query","required":false,"description":"Page size (1..200, clamped). Default 50.","schema":{"type":"integer","minimum":1,"default":50}},{"name":"offset","in":"query","required":false,"description":"Rows to skip (>= 0). Default 0.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"One page of document metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentPage"},"example":{"items":[{"id":"01KY10AAAAAAAAAAAAAAAAAAAA","path":"ops/order-platform-runbook.md","title":"Order Platform incident runbook","contentHash":"d1f9…","version":3,"updatedAt":"2026-07-20T22:03:00.000Z"}],"total":42,"limit":50,"offset":0}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createDocument","tags":["Documents"],"summary":"Create a document","description":"Writes a new markdown document into the vault (file + chunk index synchronously) and enqueues embedding + entity/relation extraction asynchronously — so the response returns immediately with the created metadata. Omit `path` to auto-derive a unique slug from the title/first heading. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","minLength":1,"description":"Vault-relative path; .md appended if missing."},"content":{"type":"string","description":"Markdown body. Defaults to a stub when omitted."},"title":{"type":"string","minLength":1,"description":"Used to seed default content when `content` is omitted."}}},"example":{"path":"ops/order-platform-oncall.md","content":"# Order Platform on-call\n\nEscalate stuck orders to the fulfillment team.\n"}}}},"responses":{"201":{"description":"The created document's metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentSaveResult"},"example":{"docId":"01KY10LLLLLLLLLLLLLLLLLLLL","path":"ops/order-platform-oncall.md","contentHash":"9ab2…","title":"Order Platform on-call"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/documents/{id}":{"get":{"operationId":"getDocument","tags":["Documents"],"summary":"Read a document","description":"Document metadata plus the raw markdown content. `missing: true` means the index row exists but the file could not be read. An unknown id is `404`. Requires scope `kb:read`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Document id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The document with its content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentWithContent"},"example":{"id":"01KY10AAAAAAAAAAAAAAAAAAAA","path":"ops/order-platform-runbook.md","title":"Order Platform incident runbook","contentHash":"d1f9…","version":3,"updatedAt":"2026-07-20T22:03:00.000Z","content":"# Order Platform incident runbook\n\nWhen orders remain STUCK…","missing":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateDocument","tags":["Documents"],"summary":"Replace a document's content","description":"Rewrites the document body, bumping its version and re-chunking, then re-embeds and re-extracts asynchronously. An unknown id is `404`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Document id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"The full replacement markdown body."}}},"example":{"content":"# Order Platform incident runbook\n\nUpdated: requeue after 12 hours.\n"}}}},"responses":{"200":{"description":"The updated document's metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentSaveResult"},"example":{"docId":"01KY10AAAAAAAAAAAAAAAAAAAA","path":"ops/order-platform-runbook.md","contentHash":"77cd…","title":"Order Platform incident runbook"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteDocument","tags":["Documents"],"summary":"Delete a document","description":"Soft-deletes the document: the file moves to trash (recoverable), chunk rows are purged (deleted content is never retrievable), and the document's graph contribution is cleaned up. An unknown id is `404`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Document id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion acknowledged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAck"},"example":{"deleted":true,"id":"01KY10AAAAAAAAAAAAAAAAAAAA"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/search":{"get":{"operationId":"searchDocuments","tags":["Search"],"summary":"Hybrid document search","description":"Full-text + vector retrieval, reciprocally fused, over the workspace's document chunks. Returns the top chunks with docId/title/path, a snippet, the fused score, and which channels matched. No answer model is invoked; an empty query returns an empty result set. Requires scope `kb:read`.\n\nPass `rerank=true` to opt into cross-encoder reranking (V2.2): a wider candidate pool is re-scored with the workspace's configured reranker (Voyage/Cohere/self-host per settings), reranked results carry a `rerankScore`, and near-duplicates are MMR-dropped. Reranking is off by default for back-compat and cost, and degrades to raw retrieval when no reranker is configured or available.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"q","in":"query","required":false,"description":"The search query. Empty/absent → empty results.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max chunks to return (1..50). Default 10. Reranked results are additionally capped at 20.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"rerank","in":"query","required":false,"description":"Opt into cross-encoder reranking of a wider candidate pool with the workspace's configured reranker. Default false (raw reciprocal-rank fusion) for back-compat and cost. When active, results carry a `rerankScore` and are MMR-deduplicated; when no reranker is available it degrades to raw retrieval.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The fused top chunks.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"},"example":{"query":"stuck orders","results":[{"chunkId":"01KY10BBBBBBBBBBBBBBBBBBBB","docId":"01KY10AAAAAAAAAAAAAAAAAAAA","docTitle":"Order Platform incident runbook","docPath":"ops/order-platform-runbook.md","headingPath":"Runbook > Stuck orders","snippet":"When orders remain in STUCK status for more than 24 hours, requeue them…","score":0.031,"channels":["fts","vector"]}],"total":1}}}},"400":{"description":"limit out of range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_params","message":"limit must be an integer between 1 and 50."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/entities":{"get":{"operationId":"listEntities","tags":["Entities"],"summary":"List canonical entities","description":"Paginated canonical entities (merged duplicates resolve to their head), highest persisted PageRank first — so the first page is the graph's most central concepts. `pagerank` is null until graph analytics have run. A graph read: accepts `kb:read` (preferred) or the legacy `runs:read` scope.","x-required-scope":"runs:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"limit","in":"query","required":false,"description":"Page size. Must be an integer >= 1; values above 200 are clamped to 200. Default 50.","schema":{"type":"integer","minimum":1,"default":50}},{"name":"offset","in":"query","required":false,"description":"Rows to skip. Must be an integer >= 0. Default 0.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"type","in":"query","required":false,"description":"Filter to one entity type (exact match), e.g. \"system\" or \"person\".","schema":{"type":"string"}}],"responses":{"200":{"description":"One page of entities plus the total count.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityPage"},"example":{"entities":[{"id":"01KY0ZW3B8AVDR67NXSE96P81N","name":"Order Platform","type":"system","pagerank":0.0421},{"id":"01KY10DDDDDDDDDDDDDDDDDDDD","name":"northwind-ops","type":"system","pagerank":0.0377}],"total":27,"limit":50,"offset":0}}}},"400":{"description":"limit/offset are not integers, limit < 1, or offset < 0.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid-pagination"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createEntity","tags":["Entities"],"summary":"Create a manual entity","description":"Adds a canonical entity to the knowledge graph by hand. A name that normalizes to an existing canonical entity of the same type is a `409 conflict` (manual entities coexist with extraction — later ingestion reuses this entity by normalized name rather than duplicating it). Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string","minLength":1,"maxLength":400,"description":"Display name."},"type":{"type":"string","minLength":1,"maxLength":120,"description":"Free-text type, e.g. \"system\"."},"aliases":{"type":"array","items":{"type":"string"},"description":"Optional alternate names (become alias rows so extraction reuses this entity)."},"description":{"type":"string","description":"Optional description (stored in the entity's attrs)."}}},"example":{"name":"Fulfillment Console","type":"system","aliases":["fulfillment-console"]}}}},"responses":{"201":{"description":"The created entity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entity"},"example":{"id":"01KY10KKKKKKKKKKKKKKKKKKKK","name":"Fulfillment Console","type":"system","nameNorm":"fulfillment console","origin":"manual","description":null,"aliases":["fulfillment-console"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"An active entity already carries this normalized name — the response includes the existing entity's id so the caller can merge or cancel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"conflict","message":"An active entity with that normalized name already exists.","existingId":"01KY0ZW3B8AVDR67NXSE96P81N"}}}}}}},"/api/v1/entities/{id}":{"get":{"operationId":"getEntity","tags":["Entities"],"summary":"Read one entity with curation metadata","description":"One entity (name, type, aliases, description, origin) plus its V2.0 `curation` block: authority tier, lifecycle status, owner/stewards, version, review stamps, supersededBy, source refs, and the steward-only editorial note. A graph read: accepts `kb:read` (preferred) or the legacy `runs:read` scope. Unknown or soft-deleted ids are `404`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The entity plus curation metadata.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Entity"},{"type":"object","required":["curation"],"properties":{"curation":{"$ref":"#/components/schemas/CurationMeta"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateEntity","tags":["Entities"],"summary":"Update an entity","description":"Edits an entity's name, type, and/or confidence. A rename that collides with an existing canonical entity is a `409 conflict`; an unknown id is `404`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":400},"type":{"type":"string","minLength":1,"maxLength":120},"aliases":{"type":"array","items":{"type":"string"}},"description":{"type":"string"}}},"example":{"type":"service"}}}},"responses":{"200":{"description":"The updated entity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entity"},"example":{"id":"01KY10KKKKKKKKKKKKKKKKKKKK","name":"Fulfillment Console","type":"service","nameNorm":"fulfillment console","origin":"manual","description":null,"aliases":["fulfillment-console"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteEntity","tags":["Entities"],"summary":"Delete an entity","description":"Soft-deletes the entity and rebuilds the serve-time canonical edges around it. An unknown id is `404`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion acknowledged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAck"},"example":{"deleted":true,"id":"01KY10KKKKKKKKKKKKKKKKKKKK"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/neighborhood":{"get":{"operationId":"getEntityNeighborhood","tags":["Entities"],"summary":"Knowledge-graph neighborhood of one entity","description":"Expands the canonical-relation frontier around one entity, both edge directions, per-hop top-K by mention count. Returns full entity cards (aliases, mention counts, top relations, source docs) for every node reached — including the seed — plus the edges and an explicit `truncated` flag when a cap was hit. A graph read: accepts `kb:read` (preferred) or the legacy `runs:read` scope.","x-required-scope":"runs:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id. A merged entity resolves to its canonical head.","schema":{"type":"string"}},{"name":"depth","in":"query","required":false,"description":"Hops to expand (1–3). Out-of-range values are rejected with 400, not clamped.","schema":{"type":"integer","minimum":1,"maximum":3,"default":1}},{"name":"perHopCap","in":"query","required":false,"description":"Max new nodes admitted per hop (1–100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"totalCap","in":"query","required":false,"description":"Max total nodes in the result (1–500).","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}}],"responses":{"200":{"description":"The seed entity's card plus the expanded frontier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Neighborhood"},"example":{"entity":{"id":"01KY0ZW3B8AVDR67NXSE96P81N","name":"Order Platform","type":"system","aliases":["order-platform","OP"],"mentionCount":42,"topRelations":["depends_on","owned_by"],"docIds":["01KY10AAAAAAAAAAAAAAAAAAAA"],"authority":"curated","lifecycleStatus":"published"},"nodes":[{"id":"01KY0ZW3B8AVDR67NXSE96P81N","name":"Order Platform","type":"system","aliases":["order-platform","OP"],"mentionCount":42,"topRelations":["depends_on","owned_by"],"docIds":["01KY10AAAAAAAAAAAAAAAAAAAA"],"authority":"curated","lifecycleStatus":"published"},{"id":"01KY10DDDDDDDDDDDDDDDDDDDD","name":"northwind-ops","type":"system","aliases":[],"mentionCount":18,"topRelations":["depends_on"],"docIds":["01KY10AAAAAAAAAAAAAAAAAAAA"],"authority":"machine_extracted","lifecycleStatus":"published"}],"edges":[{"src":"01KY0ZW3B8AVDR67NXSE96P81N","type":"depends_on","dst":"01KY10DDDDDDDDDDDDDDDDDDDD","mentionCount":7}],"truncated":false}}}},"400":{"description":"depth/perHopCap/totalCap out of range or not integers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid-params"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/manifest":{"get":{"operationId":"getWorkspaceManifest","tags":["Curation"],"summary":"The workspace knowledge-base manifest","description":"One machine-readable snapshot an agent reads before asking questions: corpus counts, the governance distribution (authority tiers, lifecycle, document verification), the top-25 hub concepts by directed in-degree over the canonical graph, and review staleness. Pure SQL — no model call. Accepts `kb:read` (preferred) or the legacy `runs:read` scope.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"The manifest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Manifest"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/entities/{id}/revisions":{"get":{"operationId":"listEntityRevisions","tags":["Curation"],"summary":"Revision history of one entity","description":"The append-only revision trail (PROV-O starting-point subset): version, change kind, full snapshot, field-level diff, activity (`ui`/`api`/`mcp`/`extraction:<runId>`/`change_request:<id>`), and actor — newest first. Requires scope `kb:read`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max revisions returned (1..200). Default 50.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Revisions, newest first.","content":{"application/json":{"schema":{"type":"object","required":["entityId","revisions"],"properties":{"entityId":{"type":"string"},"revisions":{"type":"array","items":{"$ref":"#/components/schemas/Revision"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/certify":{"post":{"operationId":"certifyEntity","tags":["Curation"],"summary":"Certify an entity","description":"Owner/admin sign-off: authority becomes `certified` (the only tier assistants state without hedging), review stamps refresh, the version bumps, and a revision + audit row land in the same transaction. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000,"description":"Optional certification note."}}}}}},"responses":{"200":{"description":"The updated curation metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationMeta"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/review":{"post":{"operationId":"reviewEntity","tags":["Curation"],"summary":"Mark an entity reviewed","description":"Stamps lastReviewedAt and the next review due date (workspace `reviewIntervalDays`). A `machine_extracted` concept is promoted to `curated` — post-hoc review promotion, the live-by-default track. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The updated curation metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationMeta"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/authority":{"post":{"operationId":"setEntityAuthority","tags":["Curation"],"summary":"Set an entity's authority tier","description":"Explicit authority set, including demotion (e.g. `certified` → `curated` on staleness). Setting the current value is an idempotent no-op (no version bump). Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["authority"],"properties":{"authority":{"$ref":"#/components/schemas/Authority"}}},"example":{"authority":"curated"}}}},"responses":{"200":{"description":"The updated curation metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationMeta"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/owner":{"post":{"operationId":"setEntityOwner","tags":["Curation"],"summary":"Assign an entity's owner and stewards","description":"Sets (or clears, with `ownerId: null`) the concept owner and optionally replaces the steward list. Owner and stewards gate change-request approval. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ownerId"],"properties":{"ownerId":{"type":["string","null"],"description":"User id, or null to clear."},"stewardIds":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Replacement steward list (omit to keep the current one)."}}},"example":{"ownerId":"user_01","stewardIds":["user_02"]}}}},"responses":{"200":{"description":"The updated curation metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationMeta"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/entities/{id}/deprecate":{"post":{"operationId":"deprecateEntity","tags":["Curation"],"summary":"Deprecate or supersede an entity","description":"Without `supersededBy`, lifecycle becomes `deprecated`. With it, lifecycle becomes `superseded` pointing at the successor — which must be a live PUBLISHED entity (`404` unknown, `400` unpublished or self-supersede). Already deprecated/superseded is a `409`. Both states stay retrievable but demoted + labeled. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Entity id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"supersededBy":{"type":"string","description":"Successor entity id (live + published)."},"note":{"type":"string","maxLength":4000}}},"example":{"supersededBy":"01KY0ZW3B8AVDR67NXSE96P81N","note":"Merged into the platform-wide term."}}}},"responses":{"200":{"description":"The updated curation metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationMeta"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/change-requests":{"get":{"operationId":"listChangeRequests","tags":["Curation"],"summary":"List change requests","description":"All change requests, newest first, optionally filtered by `status`. Each carries the target entity's current name when it still exists. Requires scope `kb:read`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"status","in":"query","required":false,"description":"Filter to one status.","schema":{"type":"string","enum":["open","approved","rejected","withdrawn"]}}],"responses":{"200":{"description":"Change requests, newest first.","content":{"application/json":{"schema":{"type":"object","required":["requests"],"properties":{"requests":{"type":"array","items":{"$ref":"#/components/schemas/ChangeRequest"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"proposeChangeRequest","tags":["Curation"],"summary":"Propose a change request","description":"Track A of the two-track gating model: schema-level/destructive graph changes are proposed, then applied by a reviewer. `payload` is validated by `kind` — create `{name, type, aliases?, description?, lifecycle?}`; update `{name?, type?, aliases?, description?}` (≥1 field); deprecate `{note?}`; supersede `{supersededBy, note?}`; delete `{}`. Non-create kinds require `entityId` naming an existing live entity (`404`). Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["create","update","deprecate","supersede","delete"]},"entityId":{"type":"string","description":"Target entity (required for every kind except create)."},"payload":{"type":"object","additionalProperties":true,"description":"Kind-specific payload (see description)."},"note":{"type":"string","maxLength":4000,"description":"Proposer's rationale."}}},"example":{"kind":"update","entityId":"01KY0ZW3B8AVDR67NXSE96P81N","payload":{"description":"The customer-facing order orchestration system."},"note":"Clarify the glossary description."}}}},"responses":{"201":{"description":"The open change request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRequest"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/change-requests/{id}/approve":{"post":{"operationId":"approveChangeRequest","tags":["Curation"],"summary":"Approve and apply a change request","description":"Atomically claims the open request, applies it through the manual/curation modules (revision activity `change_request:<id>`; a create lands at authority `curated`), and returns the applied entity id. Reviewer gate: when the target entity has an owner/stewards, only they may approve — API keys carry no member identity, so owned concepts return `409` here and approve through the workspace UI. Not-open requests are `409`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Change-request id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000}}}}}},"responses":{"200":{"description":"The approved request plus the entity it produced/affected.","content":{"application/json":{"schema":{"type":"object","required":["request","appliedEntityId"],"properties":{"request":{"$ref":"#/components/schemas/ChangeRequest"},"appliedEntityId":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/change-requests/{id}/reject":{"post":{"operationId":"rejectChangeRequest","tags":["Curation"],"summary":"Reject a change request","description":"Closes an open request as rejected (`409` when it is not open). Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Change-request id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000}}}}}},"responses":{"200":{"description":"The rejected request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRequest"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/change-requests/{id}/withdraw":{"post":{"operationId":"withdrawChangeRequest","tags":["Curation"],"summary":"Withdraw a change request","description":"Closes an open request as withdrawn (`409` when it is not open). Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Change-request id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The withdrawn request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRequest"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/documents/{id}/verify":{"post":{"operationId":"verifyDocument","tags":["Curation"],"summary":"Set a document's verification state","description":"Glean-style document verification. `verified`/`certified` stamp verifiedBy/verifiedAt and a re-verify due date derived from the workspace `reviewIntervalDays`; `unverified`/`deprecated` clear the stamps. Audited as `document.verify`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Document id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["verification"],"properties":{"verification":{"type":"string","enum":["unverified","verified","certified","deprecated"]}}},"example":{"verification":"verified"}}}},"responses":{"200":{"description":"The document's verification state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentVerification"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/documents/{id}/lineage":{"get":{"operationId":"getDocumentLineage","tags":["Lineage"],"summary":"Trace one document's lineage","description":"The unified lineage trail for one document: `origin` (connector/vault/upload provenance — which connector source produced it, external id, source version, last sync, and recent sync runs), `governance` (Glean verification tier, review-due), the document.* `audit` trail (newest first, capped at 50), `derived` knowledge (chunk count, the canonical concepts the document contributed mentions to with authority/lifecycle, and the count of live relations its evidence grounds), and `downstream` impact (how many persisted answers cited it, the dependent semantic-cache entries, and the count of live entities grounded on it — the blast radius if it were deprecated). A read: accepts `kb:read` (preferred) or the legacy `runs:read` scope. An unknown or soft-deleted id is `404`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Document id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The document's full lineage trail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentLineage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/export/skos":{"get":{"operationId":"exportSkos","tags":["Curation"],"summary":"SKOS/PROV-O JSON-LD export","description":"The workspace's published, deprecated, and superseded concepts as `skos:Concept` nodes with a static `@context`: prefLabel/altLabel, related (relations; edges typed `broader` map to `skos:broader`), `adms:status` from lifecycle, `prov:wasAttributedTo`, `dct:modified`, and `dct:isReplacedBy` for superseded concepts. Draft/pending_review concepts never export. Requires scope `kb:read`.","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"A JSON-LD document (served as application/json).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkosExport"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/relations":{"post":{"operationId":"createRelation","tags":["Relations"],"summary":"Create a relation","description":"Adds a directed edge between two existing entities and rebuilds the serve-time canonical edges for both. A missing endpoint is `404`; a duplicate edge is `409`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["srcEntityId","dstEntityId","type"],"properties":{"srcEntityId":{"type":"string","description":"Source entity id."},"dstEntityId":{"type":"string","description":"Destination entity id."},"type":{"type":"string","minLength":1,"maxLength":120,"description":"Relation type, e.g. \"depends_on\"."},"evidence":{"type":"string","description":"Optional evidence quote (no source document)."}}},"example":{"srcEntityId":"01KY0ZW3B8AVDR67NXSE96P81N","dstEntityId":"01KY10KKKKKKKKKKKKKKKKKKKK","type":"depends_on"}}}},"responses":{"201":{"description":"The created relation and the rebuilt canonical heads.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelationResult"},"example":{"relationId":"01KY10MMMMMMMMMMMMMMMMMMMM","affectedCanonicalIds":["01KY0ZW3B8AVDR67NXSE96P81N","01KY10KKKKKKKKKKKKKKKKKKKK"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/relations/{id}":{"delete":{"operationId":"deleteRelation","tags":["Relations"],"summary":"Delete a relation","description":"Soft-deletes one relation and rebuilds the serve-time canonical edges for the touched entities. An unknown id is `404`. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Relation id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion acknowledged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAck"},"example":{"deleted":true,"id":"01KY10MMMMMMMMMMMMMMMMMMMM"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/data/connectors":{"get":{"operationId":"listDataConnectors","tags":["Data"],"summary":"List data connectors","description":"The workspace's configured data connectors, credential-masked: the ciphertext is stripped and a boolean `hasCredential` says whether a secret is stored. No connection is opened. Requires scope `data:read`.","x-required-scope":"data:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"The connectors, masked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataConnectorList"},"example":{"items":[{"id":"01KY10NNNNNNNNNNNNNNNNNNNN","name":"northwind-ops","kind":"postgres","enabled":true,"hasCredential":true}],"total":1}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/data/queries":{"get":{"operationId":"listDataQueries","tags":["Data"],"summary":"List named queries","description":"The workspace's governed named queries (SELECT/WITH-only templates with typed params). Optionally filter by `connectorId`. Nothing is executed here. Requires scope `data:read`.","x-required-scope":"data:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"connectorId","in":"query","required":false,"description":"Restrict to queries bound to one connector.","schema":{"type":"string"}}],"responses":{"200":{"description":"The named queries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataQueryList"},"example":{"items":[{"id":"01KY10OOOOOOOOOOOOOOOOOOOO","slug":"shipments-by-carrier-status","title":"Shipments by carrier and status","connectorId":"01KY10NNNNNNNNNNNNNNNNNNNN","enabled":true}],"total":1}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/data/queries/{slug}/run":{"post":{"operationId":"runDataQuery","tags":["Data"],"summary":"Run a named query","description":"Executes a governed named query with typed params. The executor enforces read-only SQL, session hardening, and a row cap, and records a `data_calls` provenance row. The response carries the columns/rows plus `dataCallId` — the [Dn] provenance anchor. An unknown query is `404`; a disabled query/connector is `409`; bad params are `400`. Requires scope `data:run`.","x-required-scope":"data:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"slug","in":"path","required":true,"description":"The query's slug (or id).","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"params":{"type":"object","additionalProperties":true,"description":"Values for the query's declared params, keyed by param name."}}},"example":{"params":{"carrier":"DHL","status":"STUCK"}}}}},"responses":{"200":{"description":"The query result with provenance.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRunResult"},"example":{"dataCallId":"01KY10CCCCCCCCCCCCCCCCCCCC","connectorId":"01KY10NNNNNNNNNNNNNNNNNNNN","queryId":"01KY10OOOOOOOOOOOOOOOOOOOO","columns":["carrier","status","shipments"],"rows":[{"carrier":"DHL","status":"STUCK","shipments":14}],"rowCount":1,"durationMs":42,"truncated":false}}}},"400":{"description":"Invalid or missing query params.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid-params","message":"Missing required param: carrier"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The query or its connector is disabled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"connector-disabled","message":"Query \"shipments-by-carrier-status\" is disabled"}}}}}}},"/api/v1/reports":{"get":{"operationId":"listReports","tags":["Reports"],"summary":"List reports","description":"Report snapshots (ready and archived), newest first, without the heavy jsonb bodies. Requires scope `reports:read`.","x-required-scope":"reports:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"The report snapshots.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportList"},"example":{"items":[{"id":"01KY10PPPPPPPPPPPPPPPPPPPP","title":"Order Platform engagement — July","kind":"engagement","status":"ready","layoutVersion":7,"createdBy":null,"generatedAt":"2026-07-19T18:00:00.000Z"}],"total":1}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createReport","tags":["Reports"],"summary":"Generate a report","description":"Assembles and persists a new report snapshot from the current coverage matrix, KPIs, top entities, and graph image. No model is invoked — reports are computed from the persisted graph and corpus. Returns the full snapshot row. Requires scope `reports:write`.","x-required-scope":"reports:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200},"kind":{"type":"string","enum":["engagement","coverage"],"description":"Default engagement."}}},"example":{"title":"Order Platform engagement — July","kind":"engagement"}}}},"responses":{"201":{"description":"The persisted report snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"example":{"id":"01KY10PPPPPPPPPPPPPPPPPPPP","title":"Order Platform engagement — July","kind":"engagement","status":"ready","layoutVersion":7,"generatedAt":"2026-07-19T18:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/reports/{id}":{"get":{"operationId":"getReport","tags":["Reports"],"summary":"Read a report","description":"One full report snapshot (coverage matrix + summary jsonb included). A report in another workspace is invisible → `404`. Requires scope `reports:read`.","x-required-scope":"reports:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Report id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The full report snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"example":{"id":"01KY10PPPPPPPPPPPPPPPPPPPP","title":"Order Platform engagement — July","kind":"engagement","status":"ready","layoutVersion":7,"generatedAt":"2026-07-19T18:00:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/agents/{slug}/runs":{"post":{"operationId":"createAgentRun","tags":["Agent runs"],"summary":"Queue a durable agent run","description":"Queues a run of the named agent on its latest version and immediately returns `202` with its durable run id and reattachment URL. The worker executes the run; follow `GET /api/v1/runs/{id}/stream` to replay and tail persisted events. The compatibility query `?stream=inline` executes in this request and returns SSE, but is not the durable default. Requires scope `agents:run`.","x-required-scope":"agents:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"slug","in":"path","required":true,"description":"The agent's URL slug.","schema":{"type":"string"}},{"name":"stream","in":"query","required":false,"description":"Compatibility mode. Set to `inline` to execute in-request as SSE; omit for the durable 202 + reattach contract.","schema":{"type":"string","enum":["inline"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["input"],"properties":{"input":{"type":"string","minLength":1,"description":"The task or question for the agent."},"conversationId":{"type":"string","description":"Continue an existing conversation for multi-turn context. Omit to start fresh."}}},"example":{"input":"Summarize today's stuck orders on the Order Platform and cite the runbook."}}}},"responses":{"200":{"description":"SSE event stream only when the compatibility query `?stream=inline` is used.","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/RunEvent"},"example":"data: {\"type\":\"model_call\",\"runId\":\"01KY10EEEEEEEEEEEEEEEEEEEE\",\"textLength\":512,\"toolCalls\":1}\n\ndata: {\"type\":\"final\",\"runId\":\"01KY10EEEEEEEEEEEEEEEEEEEE\",\"status\":\"succeeded\",\"text\":\"14 orders are stuck…\",\"citations\":[{\"docId\":\"01KY10AAAAAAAAAAAAAAAAAAAA\"}]}\n\n","x-description":"Server-Sent Events stream (the default, `stream: true`). Each `data:` line is one JSON-encoded RunEvent. Intermediate `model_call` / `tool_call` events arrive as the run progresses; the stream then ends with exactly one terminal event: `final` (with status succeeded | failed | budget_exceeded | interrupted, the answer text, and citations), `suspended` (a tool call awaits human approval — resume via POST /api/v1/runs/{id}/approve), or `error` (including `no-model-configured`, which in stream mode arrives as an error event over a 200 response rather than a 409)."}}},"202":{"description":"Run accepted by the durable executor. Reattach at the returned stream path.","content":{"application/json":{"schema":{"type":"object","required":["runId","status","stream"],"properties":{"runId":{"type":"string"},"status":{"type":"string","const":"queued"},"stream":{"type":"string","description":"GET path for the durable DB-backed SSE replay/tail."}}},"example":{"runId":"01KY10EEEEEEEEEEEEEEEEEEEE","status":"queued","stream":"/api/v1/runs/01KY10EEEEEEEEEEEEEEEEEEEE/stream"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Workspace monthly spend cap reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"spend_cap_exceeded"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"No agent model configured in inline compatibility mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"no-model-configured"}}}},"429":{"description":"Workspace active-run concurrency cap reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"too_many_runs"}}}}}}},"/api/v1/runs/{id}":{"get":{"operationId":"getRun","tags":["Agent runs"],"summary":"Get a run with its steps","description":"The full run record (status, tokens, cost, timing) plus every persisted step in order. A run in another workspace is invisible and returns 404. Requires scope `runs:read`.","x-required-scope":"runs:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The run and its ordered steps.","content":{"application/json":{"schema":{"type":"object","required":["run","steps"],"properties":{"run":{"$ref":"#/components/schemas/Run"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/RunStep"}}}},"example":{"run":{"id":"01KY10EEEEEEEEEEEEEEEEEEEE","workspaceId":"01KY0ZW3B8AVDR67NXSE96P81N","agentVersionId":"01KY10FFFFFFFFFFFFFFFFFFFF","conversationId":null,"status":"succeeded","trigger":"api","input":{"input":"Summarize today's stuck orders on the Order Platform."},"output":{"text":"14 orders are currently stuck…"},"error":null,"tokensIn":5120,"tokensOut":640,"costUsd":"0.031200","startedAt":"2026-07-21T09:14:00.000Z","finishedAt":"2026-07-21T09:14:21.000Z"},"steps":[{"id":"01KY10GGGGGGGGGGGGGGGGGGGG","workspaceId":"01KY0ZW3B8AVDR67NXSE96P81N","runId":"01KY10EEEEEEEEEEEEEEEEEEEE","idx":0,"kind":"model_call","name":null,"modelId":"claude-sonnet-4-5","tokensIn":5120,"tokensOut":640,"costUsd":"0.031200","latencyMs":2100,"status":"ok","createdAt":"2026-07-21T09:14:02.000Z"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/runs/{id}/stream":{"get":{"operationId":"streamRun","tags":["Agent runs"],"summary":"Replay and tail a durable run","description":"Returns a database-backed Server-Sent Events stream for an existing run. Persisted steps are replayed in order, then the stream polls until it emits `suspended`, terminal `final`, or `error` and closes. Clients may reconnect to any web replica because no in-memory cursor is required. Requires scope `runs:read`.","x-required-scope":"runs:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Replay/tail SSE stream.","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/RunEvent"},"example":"data: {\"type\":\"model_call\",\"runId\":\"01KY10EEEEEEEEEEEEEEEEEEEE\",\"textLength\":512,\"toolCalls\":1}\n\ndata: {\"type\":\"final\",\"runId\":\"01KY10EEEEEEEEEEEEEEEEEEEE\",\"status\":\"succeeded\",\"text\":\"14 orders are stuck…\",\"citations\":[]}\n\n","x-description":"Server-Sent Events stream (the default, `stream: true`). Each `data:` line is one JSON-encoded RunEvent. Intermediate `model_call` / `tool_call` events arrive as the run progresses; the stream then ends with exactly one terminal event: `final` (with status succeeded | failed | budget_exceeded | interrupted, the answer text, and citations), `suspended` (a tool call awaits human approval — resume via POST /api/v1/runs/{id}/approve), or `error` (including `no-model-configured`, which in stream mode arrives as an error event over a 200 response rather than a 409)."}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/runs/{id}/steps":{"get":{"operationId":"listRunSteps","tags":["Agent runs"],"summary":"List a run's steps","description":"The persisted step trace only (model calls, tool calls, guardrails, approvals, retries), ordered by index. Requires scope `runs:read`.","x-required-scope":"runs:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The ordered steps.","content":{"application/json":{"schema":{"type":"object","required":["steps"],"properties":{"steps":{"type":"array","items":{"$ref":"#/components/schemas/RunStep"}}}},"example":{"steps":[{"id":"01KY10GGGGGGGGGGGGGGGGGGGG","workspaceId":"01KY0ZW3B8AVDR67NXSE96P81N","runId":"01KY10EEEEEEEEEEEEEEEEEEEE","idx":0,"kind":"tool_call","name":"kb_search","tokensIn":0,"tokensOut":0,"costUsd":"0","latencyMs":84,"status":"ok","createdAt":"2026-07-21T09:14:02.000Z"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/runs/{id}/cancel":{"post":{"operationId":"cancelRun","tags":["Agent runs"],"summary":"Cancel a run","description":"Requests cancellation of a running or suspended run. `cancelled: false` means the run had already reached a terminal state. Requires scope `agents:run`.","x-required-scope":"agents:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Whether the run was actually cancelled.","content":{"application/json":{"schema":{"type":"object","required":["cancelled"],"properties":{"cancelled":{"type":"boolean"}}},"example":{"cancelled":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/runs/{id}/approve":{"post":{"operationId":"resolveRunApproval","tags":["Agent runs"],"summary":"Approve or deny a suspended tool call","description":"Resumes a run suspended on a human-in-the-loop approval. The response is the resumed run's RunResult — which may itself be another suspension. An unknown run, unknown approval id, or a resume failure returns 404. Requires scope `agents:run`.","x-required-scope":"agents:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["approvalId","decision"],"properties":{"approvalId":{"type":"string","minLength":1,"description":"The approval id from the suspended RunResult or SSE event."},"decision":{"type":"string","enum":["allow","deny"]},"note":{"type":"string","description":"Optional note recorded with the decision."}}},"example":{"approvalId":"01KY10HHHHHHHHHHHHHHHHHHHH","decision":"allow","note":"Safe to requeue during business hours."}}}},"responses":{"200":{"description":"The resumed run's result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunResult"},"example":{"runId":"01KY10EEEEEEEEEEEEEEEEEEEE","status":"succeeded","text":"Requeued 14 stuck orders via the fulfillment console…","citations":[{"docId":"01KY10AAAAAAAAAAAAAAAAAAAA"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/NoModelConfigured"}}}},"/api/v1/runs/{id}/feedback":{"post":{"operationId":"submitRunFeedback","tags":["Agent runs"],"summary":"Record feedback on a run","description":"Attaches a feedback signal (thumb, rating, correction, edit, or citation flag) to a run. Requires scope `agents:run`.","x-required-scope":"agents:run","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Run id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["thumb","rating","correction","edit","citation_flag"]},"value":{"description":"Kind-specific payload, e.g. \"up\" for thumb or 4 for rating."},"note":{"type":"string"}}},"example":{"kind":"thumb","value":"up","note":"Correct count, right runbook."}}}},"responses":{"201":{"description":"Feedback recorded.","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The feedback record's id."}}},"example":{"id":"01KY10JJJJJJJJJJJJJJJJJJJJ"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/policy/decisions":{"get":{"operationId":"listPolicyDecisions","tags":["Policy"],"summary":"List answer-policy decisions","description":"The append-only answer-policy decision log, newest first: one row per pre/post gate decision on any surface (chat, structured query, agent), carrying the verdict, mode, calibrated confidence, the exact feature snapshot the verdict was computed from, reasons, and caveats. This is the raw material for threshold tuning (risk-coverage analysis) and shadow→enforce rollout monitoring. Requires scope `kb:read` (`runs:read` is also accepted — agent-surface rows reference runs).","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"surface","in":"query","required":false,"description":"Filter to one answering surface.","schema":{"type":"string","enum":["chat","structured","agent"]}},{"name":"verdict","in":"query","required":false,"description":"Filter to one verdict (pre or post).","schema":{"type":"string","enum":["proceed","clarify","abstain_with_pointers","answer","answer_with_caveat","abstain"]}},{"name":"limit","in":"query","required":false,"description":"Page size, 1-200 (default 50).","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"description":"Rows to skip (default 0).","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"One page of decisions, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyDecisionPage"},"example":{"items":[{"id":"01KY10KKKKKKKKKKKKKKKKKKKK","surface":"structured","conversationId":null,"runId":null,"question":"Is anything stuck on the Order Platform right now?","stage":"post","verdict":"answer","mode":"enforce","confidence":0.82,"calibrationVersion":"bootstrap-v1","features":{"topScore":0.031,"chunkCount":8,"groundedFraction":1,"onlyUnverified":false},"reasons":["confidence 0.82 >= answer floor 0.55"],"caveats":[],"createdAt":"2026-07-21T09:14:05.101Z"}],"total":1,"limit":50,"offset":0}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/policy/stats":{"get":{"operationId":"getPolicyStats","tags":["Policy"],"summary":"Answer-policy decision statistics","description":"Decision counts by verdict and by surface over the last 30 days — the quick health read for the answer policy (e.g. how often the workspace clarifies or abstains, and on which surface). Requires scope `kb:read` (`runs:read` is also accepted).","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"30-day verdict/surface counts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyStats"},"example":{"since":"2026-06-21T09:00:00.000Z","total":142,"byVerdict":{"proceed":60,"answer":55,"answer_with_caveat":14,"clarify":8,"abstain_with_pointers":3,"abstain":2},"bySurface":{"chat":90,"structured":40,"agent":12}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/evals/runs/{id}/metrics":{"get":{"operationId":"getEvalRunMetrics","tags":["Evals"],"summary":"V2.3 quality metrics for one eval run","description":"The concept-anchored quality metrics for one evaluation run, aggregated from its per-result rows: retrieval metrics (recall@k, precision@k, nDCG@10 with exponential gain, MRR, hit@k), RAGAS judge metrics when the run stored them, CRAG abstention (abstention rate + mean truthfulness in [-1,1]), the error-class histogram (retrieval_miss | hallucination | citation_error | stale | incomplete | conflict_mishandled | correct), and the overall run quality row (accuracy / groundedness / citation precision+recall). Metric fields are null when the run did not compute them (e.g. a baseline run with no graded relevance). Requires scope `kb:read` (`runs:read` is also accepted).","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Eval run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Aggregated run metrics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalRunMetrics"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/evals/runs/compare":{"get":{"operationId":"compareEvalRuns","tags":["Evals"],"summary":"Paired-significance comparison of two eval runs","description":"Compares run B against run A on a shared-item metric, pairing by golden item id (per-item mean across samples). Reports the mean delta (b−a), a 95% bootstrap confidence interval, a permutation p-value, and a two-gate `significant` verdict (the CI excludes 0 AND p<0.05). `metric` selects the paired scalar (default `truthfulness`; also `retrievalHitRate` or any per-result retrieval key: recallAtK, precisionAtK, ndcgAt10, mrr, hitAtK). Deterministic and reproducible (seeded bootstrap + permutation). Requires scope `kb:read` (`runs:read` is also accepted).","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"a","in":"query","required":true,"description":"Baseline run id (A).","schema":{"type":"string"}},{"name":"b","in":"query","required":true,"description":"Comparison run id (B).","schema":{"type":"string"}},{"name":"metric","in":"query","required":false,"description":"Paired scalar to compare (default truthfulness).","schema":{"type":"string","enum":["truthfulness","retrievalHitRate","recallAtK","precisionAtK","ndcgAt10","mrr","hitAtK"],"default":"truthfulness"}}],"responses":{"200":{"description":"The paired comparison and its significance verdict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunCompare"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/qrels":{"post":{"operationId":"authorQrel","tags":["Evals"],"summary":"Author a graded-relevance judgment (qrel)","description":"Appends a TREC-style graded-relevance judgment: for a golden item (`queryId`) and a retrieved `chunkId`, a 0–3 `grade`. The qrels table is APPEND-ONLY — a human override INSERTs a new row rather than mutating a machine judgment, and the retrieval-metrics reader resolves precedence (human > provenance > llm) at read time. `source` defaults to `human`. A duplicate within a (source, judge_model) lane is a no-op that returns the existing row with 200; a newly appended row returns 201. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["queryId","chunkId","grade"],"properties":{"queryId":{"type":"string","description":"Golden item id the judgment is for."},"chunkId":{"type":"string","description":"Retrieved chunk id being graded."},"docId":{"type":"string","description":"Owning document id (optional)."},"grade":{"type":"integer","minimum":0,"maximum":3,"description":"TREC graded relevance 0–3."},"source":{"type":"string","enum":["llm","human","provenance"],"default":"human","description":"Provenance of the judgment."},"judgeModel":{"type":"string","description":"Judge model id (machine sources only)."},"promptVersion":{"type":"string","description":"Judge prompt version (machine sources only)."}}}}}},"responses":{"200":{"description":"The pre-existing judgment (a duplicate was a no-op).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qrel"}}}},"201":{"description":"The newly appended judgment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qrel"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/connectors":{"get":{"operationId":"listConnectors","tags":["Connectors"],"summary":"List connector sources","description":"The workspace's external ingestion sources (Confluence / SharePoint / Slack / markdown upload), credential-masked: the encrypted secret column is stripped and `hasCredential` says whether a secret is stored. Read-only; no connection is opened. Requires scope `data:read`.","x-required-scope":"data:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"The credential-masked source list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorSourceList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createConnector","tags":["Connectors"],"summary":"Create a connector source","description":"Registers an external ingestion source. `credential` is a STRUCTURED per-type secret object — Confluence `{ apiToken }` (optional `email`), SharePoint `{ tenantId, clientId, clientSecret }`, Slack `{ botToken }`; `markdown_upload` is credential-less. It is JSON-serialized and encrypted at write (AES-256-GCM enc:v1) and never returned. Creating a source does NOT start a crawl — call POST /api/v1/connectors/{id}/sync for that. The response is the credential-masked source. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["confluence","sharepoint","slack","markdown_upload"],"description":"Source connector type."},"config":{"type":"object","additionalProperties":true,"description":"Non-secret source config (space keys / site ids / channel ids / base urls)."},"credential":{"oneOf":[{"$ref":"#/components/schemas/ConfluenceCredential"},{"$ref":"#/components/schemas/SharePointCredential"},{"$ref":"#/components/schemas/SlackCredential"}],"writeOnly":true,"description":"Structured per-type secret; required for confluence/sharepoint/slack, omitted for markdown_upload. Encrypted at write, never returned."},"status":{"type":"string","enum":["active","paused","error"],"default":"active"},"aclVisibility":{"type":"string","default":"workspace"}}}}}},"responses":{"201":{"description":"The created (credential-masked) source.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorSource"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/connectors/{id}":{"get":{"operationId":"getConnector","tags":["Connectors"],"summary":"Get one connector source","description":"One connector source (credential-masked) plus its recent sync-run history (newest first). A source in another workspace is invisible under RLS → 404. Requires scope `data:read`.","x-required-scope":"data:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Connector source id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The source and its sync history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorSourceDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateConnector","tags":["Connectors"],"summary":"Update a connector source","description":"Edits a source's `config`, `credential` (a STRUCTURED per-type secret object; omitted keeps the stored secret, a present one re-encrypts and must match the source's type), `status`, or `aclVisibility`. At least one field is required. Returns the credential-masked source. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Connector source id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"config":{"type":"object","additionalProperties":true},"credential":{"oneOf":[{"$ref":"#/components/schemas/ConfluenceCredential"},{"$ref":"#/components/schemas/SharePointCredential"},{"$ref":"#/components/schemas/SlackCredential"}],"writeOnly":true,"description":"Structured per-type secret; omitted keeps the stored secret."},"status":{"type":"string","enum":["active","paused","error"]},"aclVisibility":{"type":"string"}}}}}},"responses":{"200":{"description":"The updated (credential-masked) source.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorSource"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteConnector","tags":["Connectors"],"summary":"Delete a connector source","description":"Removes the source and (via FK cascade) its sync-run history. Documents already ingested from the source are not deleted here. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Connector source id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion acknowledged.","content":{"application/json":{"schema":{"type":"object","required":["deleted","id"],"properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/connectors/{id}/sync":{"post":{"operationId":"syncConnector","tags":["Connectors"],"summary":"Trigger a connector sync","description":"Enqueues a full or incremental sync for the source. `kind` defaults to `incremental` (a delta poll); `full` requests a complete re-crawl. Enqueue only — the crawl runs in the worker with a per-source singleton so overlapping syncs collapse. Returns 202 with the enqueued descriptor. Requires scope `kb:write`.","x-required-scope":"kb:write","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"},{"name":"id","in":"path","required":true,"description":"Connector source id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["full","incremental"],"default":"incremental"}}}}}},"responses":{"202":{"description":"The sync was enqueued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncEnqueued"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/cache/stats":{"get":{"operationId":"getCacheStats","tags":["Cache"],"summary":"Semantic-cache statistics","description":"V2.4 semantic answer-cache health: the current cache `mode` (off | shadow | enforce), live / invalidated / expired entry counts, how many entries carry an embedding (semantic-tier eligible), total hits, and an estimated hit rate (hits / (hits + entries ever), since each stored entry represents a prior miss). Read-only. Requires scope `kb:read` (`runs:read` is also accepted).","x-required-scope":"kb:read","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceIdHeader"}],"responses":{"200":{"description":"Cache health statistics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheStats"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"eli_sk_... (workspace key) or eli_uk_... (user key)","description":"Two kinds of bearer key are accepted, both minted in Settings and both carrying explicit scopes:\n\n- **Workspace keys** (`Authorization: Bearer eli_sk_...`) belong to one workspace and always act\n  on it. The workspace is resolved from the key — it never appears in the URL or payload.\n- **User keys** (`Authorization: Bearer eli_uk_...`) belong to a USER and may be granted one,\n  several, or all of that user's workspaces. When the grant names exactly one workspace, requests\n  need nothing extra; otherwise each request must name its target workspace with the\n  `X-Workspace-Id` header. The named workspace must be inside the key's grant, and the owner's\n  live workspace membership is re-checked on every request — leaving a workspace kills access\n  even for an explicitly granted workspace id.\n\nScopes (granular; a key may hold any subset):\n\n- `agents:run` — invoke models on the workspace's behalf (structured query, agent runs, cancel/approve/feedback).\n- `runs:read` — read agent runs and steps; also accepted on the graph reads (entities, neighborhoods) and the answer-policy reads (decisions, stats).\n- `kb:read` — read documents, full-text/vector search, the knowledge graph (entities, neighborhoods), and the answer-policy decision log and stats.\n- `kb:write` — create/edit/delete documents, entities, and relations.\n- `data:read` — list data connectors (credential-masked) and governed named queries.\n- `data:run` — execute governed named queries against connected data sources.\n- `reports:read` — list and read generated report snapshots.\n- `reports:write` — generate new report snapshots.\n\nExisting keys created before the granular scopes shipped default to `agents:run` + `runs:read` and keep working unchanged.\n\nA missing/invalid/revoked key yields `401 {\"error\":\"unauthorized\"}`; a valid key without the\noperation's scope yields `403 {\"error\":\"insufficient_scope\"}`. A multi-workspace user key that\nomits `X-Workspace-Id` yields `400 {\"error\":\"workspace_required\"}`; an `X-Workspace-Id` outside\nthe key's grant (or a lapsed membership) yields `403 {\"error\":\"workspace_forbidden\"}`."}},"parameters":{"WorkspaceIdHeader":{"name":"X-Workspace-Id","in":"header","required":false,"description":"Target workspace id — used by user keys (`eli_uk_...`) that can reach more than one workspace. Resolution rules: a workspace key (`eli_sk_...`) always acts on its own workspace (this header is ignored when it matches and rejected with `403 workspace_forbidden` when it names a different workspace); a user key whose grant names exactly one workspace uses that workspace when the header is absent; in every other case this header is REQUIRED (`400 workspace_required` when missing) and must name a workspace inside the key's grant — with the owner's live membership re-checked on every request (`403 workspace_forbidden` otherwise).","schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"Malformed JSON, a body that fails validation (Zod issues included), or a multi-workspace user key that omitted the X-Workspace-Id header (`workspace_required`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid request body","issues":[{"code":"too_small","minimum":1,"path":["question"],"message":"Too small: expected string to have >=1 characters"}]}}}},"Unauthorized":{"description":"Missing, invalid, or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"unauthorized"}}}},"Forbidden":{"description":"The API key is valid but lacks the required scope (`insufficient_scope`), or X-Workspace-Id names a workspace outside the key's grant / the owner's live membership (`workspace_forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"insufficient_scope"}}}},"NotFound":{"description":"The resource does not exist in this API key's workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_found"}}}},"NoModelConfigured":{"description":"The workspace has no enabled chat model for this operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"no-model-configured"}}}},"Conflict":{"description":"The mutation collides with existing state — e.g. a manual entity whose normalized name already names a canonical entity, or a duplicate relation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"conflict","message":"An entity with that name already exists."}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Machine-readable code (\"unauthorized\", \"insufficient_scope\", \"workspace_required\", \"workspace_forbidden\", \"not_found\", \"no-model-configured\", \"invalid-pagination\", \"invalid-params\") or a short validation message."},"issues":{"type":"array","description":"Zod validation issues — present only on 400 body-validation failures.","items":{"type":"object","additionalProperties":true}}}},"StructuredAnswer":{"type":"object","description":"One grounded answer with its full provenance: atomic claims, the [Sn] document-source registry, the [Dn] live-data registry, the entities that explain why each data source was consulted, a groundedness verdict, the answer-policy block, and usage.","required":["answer","claims","sources","dataCalls","entities","retrieval","groundedness","policy","model","usage","generatedAt"],"properties":{"answer":{"type":"string","description":"The answer text with inline [Sn]/[Dn] citation markers."},"claims":{"type":"array","description":"The answer decomposed into atomic claims; citations reference ids from sources[] and dataCalls[].","items":{"$ref":"#/components/schemas/StructuredClaim"}},"sources":{"type":"array","description":"[Sn] registry — the retrieved document chunks the answer may cite.","items":{"$ref":"#/components/schemas/SourceRef"}},"dataCalls":{"type":"array","description":"[Dn] registry — governed live-data lookups executed for this answer (empty unless includeData was true and a detected entity had bindings). At most 3.","items":{"$ref":"#/components/schemas/DataCallRef"}},"entities":{"type":"array","description":"Entities detected in the question (deterministic name/alias matching, no LLM) — the explainability trail for which data sources were consulted.","items":{"$ref":"#/components/schemas/EntitySummary"}},"retrieval":{"description":"Retrieval-confidence summary over the fused document chunks: top/mean RRF score, chunk count, and per-channel hit counts. Null when nothing was retrieved.","oneOf":[{"type":"object","required":["topScore","meanScore","chunkCount","channels"],"properties":{"topScore":{"type":"number"},"meanScore":{"type":"number"},"chunkCount":{"type":"integer"},"channels":{"type":"object","additionalProperties":{"type":"integer"}}}},{"type":"null"}]},"retrievalDebug":{"description":"Optional V2.2 retrieval-pipeline trace: the query rewrite, per-stage candidate counts, and which reranker ran. Present only when the answer went through the composed retrieval pipeline (query understanding / graph fusion / reranking); omitted for the raw-retrieval baseline. Never affects citations — the [Sn] registry in `sources` is authoritative.","oneOf":[{"$ref":"#/components/schemas/RetrievalDebug"},{"type":"null"}]},"groundedness":{"description":"Best-effort judge verdict: how many claims were verified against the evidence. Null when no judge model is configured or the check failed.","oneOf":[{"$ref":"#/components/schemas/Groundedness"},{"type":"null"}]},"policy":{"description":"The V2.1 answer-policy verdict attached to this answer (verdict, calibrated confidence, caveats, evidence conflicts; clarify/pointers on short-circuited answers). Null when the policy engine is off for this call.","oneOf":[{"$ref":"#/components/schemas/PolicyBlock"},{"type":"null"}]},"model":{"type":"object","required":["chat"],"properties":{"chat":{"type":"string","description":"Chat model id used for generation."},"judge":{"type":"string","description":"Judge model id — present only when a groundedness check ran."}}},"usage":{"description":"Token usage for the generation call; costUsd omitted when the model has no known pricing.","oneOf":[{"type":"object","required":["inputTokens","outputTokens"],"properties":{"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"costUsd":{"type":"number"}}},{"type":"null"}]},"generatedAt":{"type":"string","format":"date-time"}}},"Groundedness":{"type":"object","description":"Judge verdict: verified of total claims held up against the provided evidence.","required":["verified","total"],"properties":{"verified":{"type":"integer","description":"Claims the judge verified against the evidence."},"total":{"type":"integer","description":"Claims checked."}}},"RetrievalDebug":{"type":"object","description":"Trace of the V2.2 retrieval pipeline that produced this answer's evidence: query understanding (one judge call → rewrite + sub-queries + advisory filters), the candidate-pool → graph-fusion → rerank → token-budget-assembly stage counts, and the reranker that ran. Diagnostic only; it never changes which chunks are citable.","required":["understanding","stages"],"properties":{"understanding":{"description":"Query-understanding output, or null when it was disabled or no judge model was available (the raw question was used verbatim).","oneOf":[{"type":"object","required":["rewrite","subQueries","filters","isAmbiguous"],"properties":{"rewrite":{"type":"string","description":"The rewritten, retrieval-optimized query (replaces the raw question when non-empty)."},"subQueries":{"type":"array","items":{"type":"string"},"description":"Decomposed sub-queries whose FTS hits are unioned into the pool (bounded to 3)."},"filters":{"type":"object","description":"Advisory metadata filters (soft boost / optional scope — never a hard exclusion).","properties":{"pathPrefix":{"type":"string"},"entityTypes":{"type":"array","items":{"type":"string"}},"docTitleContains":{"type":"string"}}},"isAmbiguous":{"type":"boolean","description":"The judge flagged the question as ambiguous (candidate for a clarify prompt)."}}},{"type":"null"}]},"stages":{"type":"object","description":"Per-stage counters for the composed pipeline.","required":["candidatePool","graphAdded","reranked","assembledTokens"],"properties":{"candidatePool":{"type":"integer","description":"Distinct candidate chunks fed to rerank/assembly (after understanding + graph fusion)."},"graphAdded":{"type":"integer","description":"Chunks contributed by graph-fused retrieval that survived into the pool."},"reranked":{"type":"boolean","description":"True only when a real (non-`none`) reranker actually re-scored the pool."},"assembledTokens":{"type":"integer","description":"Estimated tokens in the final assembled context (chars/4)."}}},"reranker":{"type":"string","description":"The reranker kind that ran, e.g. \"voyage\", \"cohere\", \"onnx-bge\", or \"none\"."}}},"PolicyBlock":{"type":"object","description":"The V2.1 answer-policy verdict attached to an answer. It NEVER mutates model prose — it annotates: a verdict (pre-gate: proceed | clarify | abstain_with_pointers; post-gate: answer | answer_with_caveat | abstain), a calibrated 0-1 confidence (hybrid: retrieval signals + groundedness, with model-verbalized confidence as one feature only), machine-readable reasons, caveats, and detected evidence conflicts. Short-circuited answers (enforce mode) additionally carry `clarify` (a question with options) or `pointers` (top documents to read instead of a bare \"I don't know\").","required":["mode","verdict","confidence","calibrationVersion","reasons","caveats","conflicts"],"properties":{"mode":{"type":"string","enum":["off","shadow","enforce"],"description":"The policy mode this decision was computed under (shadow = logged, behavior unchanged)."},"verdict":{"type":"string","enum":["proceed","clarify","abstain_with_pointers","answer","answer_with_caveat","abstain"],"description":"Pre-gate or post-gate verdict."},"confidence":{"type":["number","null"],"description":"Calibrated confidence 0-1 (logistic over the policy feature snapshot). Null on pre-gate short-circuits, where no confidence was computed. Capped below the answer floor when only unverified sources were retrieved (authority weighting)."},"calibrationVersion":{"type":"string","description":"Version of the confidence calibration that scored this answer, e.g. \"bootstrap-v1\"."},"reasons":{"type":"array","items":{"type":"string"},"description":"Machine-readable reasons behind the verdict (thresholds crossed, caps applied, gate signals)."},"caveats":{"type":"array","items":{"$ref":"#/components/schemas/PolicyCaveat"},"description":"Caveats a consumer should surface alongside the answer."},"conflicts":{"type":"array","items":{"$ref":"#/components/schemas/EvidenceConflict"},"description":"Evidence conflicts detected among the sources this answer cites."},"clarify":{"description":"Present on a clarify verdict: the clarifying question to ask, with candidate options.","oneOf":[{"type":"object","required":["question","options"],"properties":{"question":{"type":"string"},"options":{"type":"array","items":{"type":"string"}}}},{"type":"null"}]},"pointers":{"type":"array","description":"Present on abstain_with_pointers: the best documents to consult instead of an unsupported answer.","items":{"type":"object","required":["docId","title","path"],"properties":{"docId":{"type":"string"},"title":{"type":"string"},"path":{"type":"string"}}}}}},"PolicyCaveat":{"type":"object","description":"One caveat attached to an answer by the policy post-gate.","required":["kind","detail"],"properties":{"kind":{"type":"string","enum":["unsupported_claims","no_verified_source","conflicting_evidence","low_confidence"]},"detail":{"type":"string","description":"Human-readable explanation of the caveat."},"claimIndexes":{"type":"array","items":{"type":"integer"},"description":"Indexes into StructuredAnswer.claims — present on unsupported_claims."}}},"EvidenceConflict":{"type":"object","description":"Two evidence chunks that disagree about the same claim. Detected only for claims citing 2+ distinct documents; the generator is told about detected conflicts so the answer presents both accounts with citations.","required":["claimText","chunkA","chunkB","docA","docB","kind","stanceA","stanceB"],"properties":{"claimText":{"type":"string","description":"The claim the two chunks disagree about."},"chunkA":{"type":"string","description":"First conflicting chunk id."},"chunkB":{"type":"string","description":"Second conflicting chunk id."},"docA":{"type":"string","description":"Document id of chunkA."},"docB":{"type":"string","description":"Document id of chunkB."},"kind":{"type":"string","enum":["direct","partial","temporal"],"description":"direct = flat contradiction; partial = incompatible details; temporal = different points in time."},"stanceA":{"type":"string","description":"What chunkA asserts."},"stanceB":{"type":"string","description":"What chunkB asserts."}}},"PolicyDecision":{"type":"object","description":"One append-only answer-policy decision: a pre or post gate verdict with the exact feature snapshot it was computed from.","required":["id","surface","conversationId","runId","question","stage","verdict","mode","confidence","calibrationVersion","features","reasons","caveats","createdAt"],"properties":{"id":{"type":"string"},"surface":{"type":"string","enum":["chat","structured","agent"]},"conversationId":{"type":["string","null"],"description":"Chat conversation the decision belongs to (chat surface only)."},"runId":{"type":["string","null"],"description":"Agent run the decision belongs to (agent surface only)."},"question":{"type":"string","description":"The question, truncated to 2000 characters."},"stage":{"type":"string","enum":["pre","post"]},"verdict":{"type":"string","enum":["proceed","clarify","abstain_with_pointers","answer","answer_with_caveat","abstain"]},"mode":{"type":"string","enum":["off","shadow","enforce"]},"confidence":{"type":["number","null"],"description":"Calibrated confidence — null on pre-stage rows."},"calibrationVersion":{"type":["string","null"],"description":"Null on pre-stage rows."},"features":{"type":"object","additionalProperties":true,"description":"The (possibly partial) policy feature snapshot: topScore, scoreMargin, meanTopK, chunkCount, countAboveFloor, channelAgreement, maxVerificationRank, fractionVerified, onlyUnverified, hasCertifiedConcept, groundedFraction, verbalizedConfidence, relevantChunkFraction."},"reasons":{"type":"array","items":{"type":"string"}},"caveats":{"type":"array","items":{"$ref":"#/components/schemas/PolicyCaveat"}},"createdAt":{"type":"string","format":"date-time"}}},"PolicyDecisionPage":{"type":"object","required":["items","total","limit","offset"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PolicyDecision"}},"total":{"type":"integer","description":"Total decisions matching the filter."},"limit":{"type":"integer","description":"Effective page size after clamping (1-200)."},"offset":{"type":"integer"}}},"PolicyStats":{"type":"object","description":"Answer-policy decision counts over the trailing 30-day window.","required":["since","total","byVerdict","bySurface"],"properties":{"since":{"type":"string","format":"date-time","description":"Start of the 30-day window."},"total":{"type":"integer","description":"Decisions in the window."},"byVerdict":{"type":"object","additionalProperties":{"type":"integer"},"description":"Counts keyed by verdict (proceed, clarify, abstain_with_pointers, answer, answer_with_caveat, abstain)."},"bySurface":{"type":"object","additionalProperties":{"type":"integer"},"description":"Counts keyed by surface (chat, structured, agent)."}}},"RetrievalMetricValues":{"type":"object","description":"Mean per-result retrieval metrics vs graded relevance (qrels). Each is null when no result carried that metric.","required":["recallAtK","precisionAtK","ndcgAt10","mrr","hitAtK"],"properties":{"recallAtK":{"type":["number","null"]},"precisionAtK":{"type":["number","null"]},"ndcgAt10":{"type":["number","null"],"description":"nDCG@10 with exponential gain 2^rel−1."},"mrr":{"type":["number","null"]},"hitAtK":{"type":["number","null"]}}},"RagasMetricValues":{"type":"object","description":"Mean RAGAS judge metrics over the run's results (present only when the run computed them).","required":["faithfulness","responseRelevancy","contextPrecision","contextRecall","noiseSensitivity"],"properties":{"faithfulness":{"type":["number","null"]},"responseRelevancy":{"type":["number","null"]},"contextPrecision":{"type":["number","null"]},"contextRecall":{"type":["number","null"]},"noiseSensitivity":{"type":["number","null"]}}},"RunAbstention":{"type":"object","description":"CRAG abstention aggregate over the run's results.","required":["total","abstained","answered","abstentionRate","meanTruthfulness"],"properties":{"total":{"type":"integer","description":"Results counted."},"abstained":{"type":"integer"},"answered":{"type":"integer"},"abstentionRate":{"type":["number","null"],"description":"abstained / (abstained + answered); null when nothing declared abstention state."},"meanTruthfulness":{"type":["number","null"],"description":"Mean CRAG truthfulness in [-1,1] (perfect 1 / acceptable 0.5 / missing 0 / incorrect -1)."}}},"RunQuality":{"type":"object","description":"The overall run-metrics row (tag=null) — the run's headline scores.","required":["accuracy","groundedness","citationPrecision","citationRecall","retrievalHitRate","nItems"],"properties":{"accuracy":{"type":["number","null"]},"groundedness":{"type":["number","null"]},"citationPrecision":{"type":["number","null"]},"citationRecall":{"type":["number","null"]},"retrievalHitRate":{"type":["number","null"]},"nItems":{"type":"integer"}}},"EvalRunMetrics":{"type":"object","description":"V2.3 concept-anchored quality metrics for one eval run, aggregated from its per-result rows.","required":["runId","status","samplesN","resultsCounted","retrieval","ragas","abstention","errorClasses","quality"],"properties":{"runId":{"type":"string"},"status":{"type":"string","enum":["running","succeeded","failed","degraded"]},"samplesN":{"type":"integer","description":"Samples per golden item this run used."},"resultsCounted":{"type":"integer","description":"Result rows aggregated."},"retrieval":{"oneOf":[{"$ref":"#/components/schemas/RetrievalMetricValues"},{"type":"null"}]},"ragas":{"oneOf":[{"$ref":"#/components/schemas/RagasMetricValues"},{"type":"null"}]},"abstention":{"$ref":"#/components/schemas/RunAbstention"},"errorClasses":{"type":"object","additionalProperties":{"type":"integer"},"description":"Histogram of dominant error class (retrieval_miss | hallucination | citation_error | stale | incomplete | conflict_mishandled | correct)."},"quality":{"oneOf":[{"$ref":"#/components/schemas/RunQuality"},{"type":"null"}]}}},"RunCompare":{"type":"object","description":"Paired-significance comparison of run B against run A on a shared-item metric. Two-gate significance = CI excludes 0 AND p<0.05.","required":["a","b","metric","pairedN","meanA","meanB","deltaMean","ci","pValue","significant","method"],"properties":{"a":{"type":"object","required":["runId","n"],"properties":{"runId":{"type":"string"},"n":{"type":"integer","description":"Items scored in run A."}}},"b":{"type":"object","required":["runId","n"],"properties":{"runId":{"type":"string"},"n":{"type":"integer","description":"Items scored in run B."}}},"metric":{"type":"string","description":"The paired scalar compared."},"pairedN":{"type":"integer","description":"Golden items scored in BOTH runs."},"meanA":{"type":["number","null"]},"meanB":{"type":["number","null"]},"deltaMean":{"type":["number","null"],"description":"Mean of (b−a) over paired items."},"ci":{"description":"95% bootstrap CI on the mean delta; null when fewer than 2 paired items.","oneOf":[{"type":"object","required":["low","high","level"],"properties":{"low":{"type":"number"},"high":{"type":"number"},"level":{"type":"number"}}},{"type":"null"}]},"pValue":{"type":["number","null"],"description":"Two-sided sign-flip permutation p-value."},"significant":{"type":"boolean"},"method":{"type":"string"}}},"Qrel":{"type":"object","description":"One append-only TREC graded-relevance judgment.","required":["id","workspaceId","queryId","chunkId","docId","grade","source","judgeModel","promptVersion","createdAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"queryId":{"type":"string","description":"Golden item id."},"chunkId":{"type":"string"},"docId":{"type":["string","null"]},"grade":{"type":"integer","minimum":0,"maximum":3},"source":{"type":"string","enum":["llm","human","provenance"]},"judgeModel":{"type":["string","null"]},"promptVersion":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"ConfluenceCredential":{"type":"object","description":"Confluence secret: an Atlassian API token (Cloud) or bearer PAT (Server/DC). `email` is used for Cloud HTTP-basic auth.","required":["apiToken"],"properties":{"email":{"type":"string","description":"Atlassian account email (Cloud HTTP basic); omit for a Server/DC bearer PAT."},"apiToken":{"type":"string","writeOnly":true}}},"SharePointCredential":{"type":"object","description":"SharePoint / Microsoft Graph app-only (client-credentials) secret.","required":["tenantId","clientId","clientSecret"],"properties":{"tenantId":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string","writeOnly":true}}},"SlackCredential":{"type":"object","description":"Slack per-customer internal-app bot token (xoxb-…).","required":["botToken"],"properties":{"botToken":{"type":"string","writeOnly":true}}},"ConnectorSource":{"type":"object","description":"An external ingestion source, credential-masked: the encrypted secret is never present; `hasCredential` says whether one is stored.","required":["id","workspaceId","type","config","syncState","status","aclVisibility","hasCredential","lastSyncedAt","createdBy","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"type":{"type":"string","enum":["confluence","sharepoint","slack","markdown_upload"]},"config":{"type":"object","additionalProperties":true,"description":"Non-secret source config."},"syncState":{"type":"object","additionalProperties":true,"description":"Resumable checkpoint (deltaLink / CQL watermark / per-channel cursors) — written by the worker."},"status":{"type":"string","enum":["active","paused","error"]},"aclVisibility":{"type":"string","enum":["workspace","restricted"],"description":"Default source visibility. restricted forces ingested documents through actor-principal retrieval filtering."},"hasCredential":{"type":"boolean"},"lastSyncedAt":{"type":["string","null"],"format":"date-time"},"createdBy":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ConnectorSourceDetail":{"allOf":[{"$ref":"#/components/schemas/ConnectorSource"},{"type":"object","required":["syncRuns"],"properties":{"syncRuns":{"type":"array","description":"Recent sync-run history, newest first.","items":{"$ref":"#/components/schemas/SyncRun"}}}}]},"ConnectorSourceList":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorSource"}},"total":{"type":"integer"}}},"SyncRun":{"type":"object","description":"One append-only connector sync record.","required":["id","workspaceId","sourceId","kind","startedAt","finishedAt","stats","error"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"sourceId":{"type":"string"},"kind":{"type":"string","enum":["full","incremental","prune","permissions"]},"startedAt":{"type":"string","format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"stats":{"type":"object","additionalProperties":true,"description":"{ docsSeen, docsAdded, docsUpdated, docsTombstoned, ... }."},"error":{"type":["string","null"]}}},"SyncEnqueued":{"type":"object","required":["enqueued","sourceId","kind"],"properties":{"enqueued":{"type":"boolean"},"sourceId":{"type":"string"},"kind":{"type":"string","enum":["full","incremental"]}}},"CacheStats":{"type":"object","description":"V2.4 semantic answer-cache health statistics.","required":["mode","active","invalidated","expired","total","withEmbedding","totalHits","hitRate","lastHitAt"],"properties":{"mode":{"type":"string","enum":["off","shadow","enforce"]},"active":{"type":"integer","description":"Live entries (not invalidated, not expired)."},"invalidated":{"type":"integer"},"expired":{"type":"integer"},"total":{"type":"integer","description":"All entries ever written."},"withEmbedding":{"type":"integer","description":"Entries carrying an embedding (semantic-tier eligible)."},"totalHits":{"type":"integer","description":"Sum of hit counts across entries."},"hitRate":{"type":["number","null"],"description":"Estimated: hits / (hits + entries ever). Null when there is no data."},"lastHitAt":{"type":["string","null"],"format":"date-time"}}},"StructuredClaim":{"type":"object","required":["text","citations"],"properties":{"text":{"type":"string","description":"One atomic factual claim from the answer."},"citations":{"type":"array","description":"Supporting citation ids, e.g. [\"S1\", \"D2\"]. Only ids present in this answer's registries appear.","items":{"type":"string"}}}},"SourceRef":{"type":"object","description":"One [Sn] document source.","required":["id","docId","docTitle","docPath","chunkId","snippet"],"properties":{"id":{"type":"string","description":"Citation marker, \"S1\"..\"Sn\"."},"docId":{"type":"string"},"docTitle":{"type":"string"},"docPath":{"type":"string"},"chunkId":{"type":"string"},"snippet":{"type":"string","description":"First 200 characters of the cited chunk."}}},"DataCallRef":{"type":"object","description":"One [Dn] governed live-data lookup. dataCallId is the persisted provenance row — fetchable in the workspace UI's data-call audit trail.","required":["id","dataCallId","connectorName","queryTitle","rowCount","executedAt"],"properties":{"id":{"type":"string","description":"Citation marker, \"D1\"..\"Dn\"."},"dataCallId":{"type":"string","description":"Persisted data_calls provenance row id."},"connectorName":{"type":"string","description":"Connector the query ran against, e.g. \"northwind-ops\"."},"queryTitle":{"type":"string","description":"Human title of the governed read-only query."},"rowCount":{"type":"integer"},"executedAt":{"type":"string","format":"date-time"}}},"EntitySummary":{"type":"object","description":"A canonical entity with its persisted PageRank (null until graph analytics have run). Where the entity row is known (structured answers), the V2.0 governance labels are included.","required":["id","name","type"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"pagerank":{"type":["number","null"]},"authority":{"$ref":"#/components/schemas/Authority"},"lifecycleStatus":{"$ref":"#/components/schemas/LifecycleStatus"}}},"EntityPage":{"type":"object","required":["entities","total","limit","offset"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntitySummary"}},"total":{"type":"integer","description":"Total canonical entities matching the filter."},"limit":{"type":"integer","description":"Effective page size after clamping."},"offset":{"type":"integer"}}},"EntityCard":{"type":"object","description":"A full entity card as returned by graph reads. Soft-deleted and draft/pending_review entities are never served as cards.","required":["id","name","type","aliases","mentionCount","topRelations","docIds","authority","lifecycleStatus"],"properties":{"authority":{"$ref":"#/components/schemas/Authority"},"lifecycleStatus":{"$ref":"#/components/schemas/LifecycleStatus"},"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"},"description":"Up to 5 aliases."},"mentionCount":{"type":"integer","description":"Mentions across the corpus, rolled up over the merged cluster."},"topRelations":{"type":"array","items":{"type":"string"},"description":"Up to 8 most-mentioned relation types touching this entity."},"docIds":{"type":"array","items":{"type":"string"},"description":"Up to 5 top source documents."}}},"FrontierEdge":{"type":"object","description":"One canonical relation between two entities in a neighborhood result.","required":["src","type","dst","mentionCount"],"properties":{"src":{"type":"string","description":"Source entity id."},"type":{"type":"string","description":"Relation type, e.g. \"depends_on\"."},"dst":{"type":"string","description":"Destination entity id."},"mentionCount":{"type":"integer","description":"Times this relation was extracted from the corpus."}}},"Neighborhood":{"type":"object","description":"The knowledge-graph frontier around one entity. nodes[] includes the seed entity's card; truncated is true when a per-hop or total cap cut the expansion (never a mid-JSON truncation).","required":["entity","nodes","edges","truncated"],"properties":{"entity":{"$ref":"#/components/schemas/EntityCard"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/EntityCard"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/FrontierEdge"}},"truncated":{"type":"boolean"}}},"DeleteAck":{"type":"object","description":"Acknowledgement of a soft delete.","required":["deleted","id"],"properties":{"deleted":{"type":"boolean"},"id":{"type":"string","description":"The id that was deleted."}}},"Entity":{"type":"object","description":"A knowledge-graph entity as returned by the manual mutation endpoints. `origin` is \"manual\" for API-created entities; `type` is free text; `nameNorm` is the normalized key used for dedupe/reuse.","required":["id","name","type","nameNorm","origin","aliases"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"nameNorm":{"type":"string","description":"Normalized name — the reuse/conflict key."},"origin":{"type":"string","description":"\"manual\" or \"extraction\"."},"description":{"type":["string","null"]},"aliases":{"type":"array","items":{"type":"string"}}}},"Authority":{"type":"string","enum":["machine_extracted","asserted","curated","certified"],"description":"V2.0 authority tier (Atlan certificateStatus / OpenMetadata certification semantics): machine_extracted < asserted < curated < certified. Only `certified` may be stated by assistants without hedging."},"LifecycleStatus":{"type":"string","enum":["draft","pending_review","published","deprecated","superseded"],"description":"Concept lifecycle (EU Publications Office / ISO 25964 / W3C ADMS status). draft/pending_review are excluded from retrieval, cards, manifest hubs, and autocomplete; deprecated/superseded stay retrievable but demoted + labeled."},"CurationMeta":{"type":"object","description":"V2.0 governance metadata of one entity.","required":["authority","lifecycleStatus","ownerId","stewardIds","version","lastReviewedAt","nextReviewAt","supersededBy","sourceRefs","editorialNote"],"properties":{"authority":{"$ref":"#/components/schemas/Authority"},"lifecycleStatus":{"$ref":"#/components/schemas/LifecycleStatus"},"ownerId":{"type":["string","null"]},"stewardIds":{"type":"array","items":{"type":"string"}},"version":{"type":"integer","description":"Bumped by every recorded revision."},"lastReviewedAt":{"type":["string","null"],"format":"date-time"},"nextReviewAt":{"type":["string","null"],"format":"date-time","description":"Review-SLA due date."},"supersededBy":{"type":["string","null"],"description":"Successor entity id when lifecycle is superseded."},"sourceRefs":{"type":"array","items":{"type":"object","required":["label"],"properties":{"label":{"type":"string"},"url":{"type":"string"}}}},"editorialNote":{"type":["string","null"],"description":"SKOS editorialNote — steward-only; never rendered to end users or into LLM context."}}},"Revision":{"type":"object","description":"One append-only entity revision (PROV-O starting-point subset: changedBy → wasAttributedTo, activity → wasGeneratedBy, createdAt → generatedAtTime).","required":["id","entityId","version","changeKind","snapshot","diff","createdAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"entityId":{"type":"string"},"version":{"type":"integer"},"changeKind":{"type":"string","enum":["create","update","review","certify","set_authority","set_owner","deprecate","supersede","delete","change_request","verify"]},"snapshot":{"type":"object","additionalProperties":true,"description":"Full row snapshot at this version (name, type, attrs, authority, lifecycle, owner, stewards, aliases, sourceRefs, supersededBy). The steward-only editorialNote is excluded."},"diff":{"type":"object","additionalProperties":true,"description":"OpenMetadata changeDescription style: {field: {from, to}} vs the previous snapshot."},"activity":{"type":["string","null"],"description":"PROV wasGeneratedBy: 'ui' | 'api' | 'mcp' | 'extraction:<runId>' | 'change_request:<id>'."},"changedBy":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"ChangeRequest":{"type":"object","description":"A proposed schema-level/destructive graph change awaiting (or past) review.","required":["id","entityId","kind","payload","status","createdAt"],"properties":{"id":{"type":"string"},"entityId":{"type":["string","null"],"description":"Null for create proposals."},"kind":{"type":"string","enum":["create","update","deprecate","supersede","delete"]},"payload":{"type":"object","additionalProperties":true},"status":{"type":"string","enum":["open","approved","rejected","withdrawn"]},"proposedBy":{"type":["string","null"]},"note":{"type":["string","null"]},"reviewedBy":{"type":["string","null"]},"reviewNote":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"reviewedAt":{"type":["string","null"],"format":"date-time"},"entityName":{"type":["string","null"],"description":"Current name of the target entity, when it exists."}}},"DocumentVerification":{"type":"object","description":"A document's verification state (Glean verification model).","required":["docId","verification","verifiedBy","verifiedAt","nextVerifyAt"],"properties":{"docId":{"type":"string"},"verification":{"type":"string","enum":["unverified","verified","certified","deprecated"]},"verifiedBy":{"type":["string","null"]},"verifiedAt":{"type":["string","null"],"format":"date-time"},"nextVerifyAt":{"type":["string","null"],"format":"date-time"}}},"ManifestConcept":{"type":"object","description":"One hub concept in the workspace manifest, ranked by directed in-degree.","required":["id","name","type","summary","authority","lifecycleStatus","version","inDegree","outDegree","mentionCount","lastReviewedAt","ownerId"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"summary":{"type":["string","null"],"description":"The entity's description, when set."},"authority":{"$ref":"#/components/schemas/Authority"},"lifecycleStatus":{"$ref":"#/components/schemas/LifecycleStatus"},"version":{"type":"integer"},"inDegree":{"type":"integer","description":"Directed in-degree over canonical relations."},"outDegree":{"type":"integer"},"mentionCount":{"type":"integer","description":"Corpus mentions rolled up over the merged cluster."},"lastReviewedAt":{"type":["string","null"],"format":"date-time"},"ownerId":{"type":["string","null"]}}},"Manifest":{"type":"object","description":"The machine-readable knowledge-base snapshot (GET /api/v1/manifest).","required":["generatedAt","workspace","counts","hubConcepts","staleness"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"workspace":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string"},"name":{"type":"string"}}},"counts":{"type":"object","required":["documents","chunks","entities","relations","entitiesByType","relationsByType","byAuthority","byLifecycle","documentsByVerification"],"properties":{"documents":{"type":"integer"},"chunks":{"type":"integer"},"entities":{"type":"integer","description":"Live canonical entities."},"relations":{"type":"integer","description":"Canonical (serve-time) edges."},"entitiesByType":{"type":"object","additionalProperties":{"type":"integer"}},"relationsByType":{"type":"object","additionalProperties":{"type":"integer"}},"byAuthority":{"type":"object","additionalProperties":{"type":"integer"}},"byLifecycle":{"type":"object","additionalProperties":{"type":"integer"}},"documentsByVerification":{"type":"object","additionalProperties":{"type":"integer"}}}},"hubConcepts":{"type":"array","items":{"$ref":"#/components/schemas/ManifestConcept"},"description":"Top 25 live published entities by directed in-degree (ties by mention count)."},"staleness":{"type":"object","required":["overdueReviews","neverReviewed"],"properties":{"overdueReviews":{"type":"integer","description":"Published concepts past next_review_at."},"neverReviewed":{"type":"integer","description":"Live concepts with no review stamp."}}}}},"SkosExport":{"type":"object","description":"SKOS/PROV-O JSON-LD (static @context: skos, adms, prov, dct). `@graph` holds one skos:Concept per published/deprecated/superseded concept — prefLabel, altLabel from aliases, related (broader for edges typed `broader`), adms:status from lifecycle, prov:wasAttributedTo, dct:modified, dct:isReplacedBy for superseded concepts.","required":["@context","generatedAt","workspaceId","@graph"],"properties":{"@context":{"type":"object","additionalProperties":{"type":"string"}},"generatedAt":{"type":"string","format":"date-time"},"workspaceId":{"type":"string"},"lifecycles":{"type":"array","items":{"type":"string"}},"@graph":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"RelationResult":{"type":"object","description":"The result of creating a relation: the new relation id plus the canonical entity heads whose serve-time edges were rebuilt.","required":["relationId","affectedCanonicalIds"],"properties":{"relationId":{"type":"string"},"affectedCanonicalIds":{"type":"array","items":{"type":"string"}}}},"DocumentMeta":{"type":"object","description":"Document index metadata (no content).","required":["id","path","title","contentHash","version","updatedAt"],"properties":{"id":{"type":"string"},"path":{"type":"string","description":"Vault-relative path."},"title":{"type":"string"},"contentHash":{"type":"string","description":"SHA-256 of the stored content."},"version":{"type":"integer","description":"Bumped on every save."},"updatedAt":{"type":"string","format":"date-time"}}},"DocumentWithContent":{"allOf":[{"$ref":"#/components/schemas/DocumentMeta"},{"type":"object","required":["content","missing"],"properties":{"content":{"type":"string","description":"The raw markdown body ('' when the file is missing)."},"missing":{"type":"boolean","description":"True when the index row exists but the file could not be read."}}}]},"DocumentPage":{"type":"object","required":["items","total","limit","offset"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DocumentMeta"}},"total":{"type":"integer","description":"Total live documents."},"limit":{"type":"integer"},"offset":{"type":"integer"}}},"DocumentSaveResult":{"type":"object","description":"The metadata returned by a document create/update.","required":["docId","path","contentHash","title"],"properties":{"docId":{"type":"string"},"path":{"type":"string"},"contentHash":{"type":"string"},"title":{"type":"string"}}},"DocumentLineage":{"type":"object","description":"The unified per-document lineage trail (GET /api/v1/documents/{id}/lineage): origin provenance, governance, immutable revision summaries, the document audit trail, derived knowledge, and downstream impact.","required":["document","governance","origin","revisions","audit","derived","downstream"],"properties":{"document":{"type":"object","required":["id","path","title","version","contentHash","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"path":{"type":"string","description":"Vault-relative path."},"title":{"type":"string"},"version":{"type":"integer","description":"Bumped on every save."},"contentHash":{"type":"string","description":"SHA-256 of the stored content."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdBy":{"type":["string","null"]},"updatedBy":{"type":["string","null"]}}},"governance":{"type":"object","description":"Glean-style document verification + review SLA.","required":["verification","reviewOverdue"],"properties":{"verification":{"type":"string","enum":["unverified","verified","certified","deprecated"]},"verifiedBy":{"type":["string","null"]},"verifiedAt":{"type":["string","null"],"format":"date-time"},"nextVerifyAt":{"type":["string","null"],"format":"date-time"},"reviewOverdue":{"type":"boolean","description":"True when a verified/certified doc is past its re-verify due date."}}},"origin":{"type":"object","description":"Where the document came from (INTAKE provenance).","required":["kind","recentSyncRuns"],"properties":{"kind":{"type":"string","enum":["connector","vault","upload"],"description":"connector = external source; upload = markdown_upload connector; vault = local/file doc."},"sourceId":{"type":["string","null"],"description":"connector_sources row id (null for vault docs)."},"sourceType":{"type":["string","null"],"description":"confluence | sharepoint | slack | markdown_upload (null for vault docs)."},"externalId":{"type":["string","null"]},"sourceVersion":{"type":["string","null"]},"lastSyncedAt":{"type":["string","null"],"format":"date-time"},"recentSyncRuns":{"type":"array","description":"Up to 10 most recent sync runs for the source, newest first.","items":{"type":"object","required":["id","kind","startedAt"],"properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["full","incremental","prune","permissions"]},"startedAt":{"type":"string","format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"error":{"type":["string","null"]}}}}}},"revisions":{"type":"object","description":"Immutable document history. `items` is newest first and capped at 50; `total` counts the complete stream.","required":["total","items"],"properties":{"total":{"type":"integer","minimum":0},"items":{"type":"array","items":{"type":"object","required":["id","version","changeKind","changedFields","hasContent","createdAt"],"properties":{"id":{"type":"string"},"version":{"type":"integer","minimum":1},"changeKind":{"type":"string","description":"create | update | delete (forward-compatible)."},"changedFields":{"type":"array","items":{"type":"string"}},"hasContent":{"type":"boolean","description":"Whether this revision retains a content snapshot for diffing."},"activity":{"type":["string","null"]},"changedBy":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}}}}},"audit":{"type":"array","description":"document.* audit events targeting this doc, newest first, capped at 50.","items":{"type":"object","required":["event","at","meta"],"properties":{"event":{"type":"string","description":"e.g. document.verify, document.delete."},"actor":{"type":["string","null"]},"at":{"type":"string","format":"date-time"},"meta":{"type":"object","additionalProperties":true}}}},"derived":{"type":"object","description":"The knowledge this document produced (ATLAS).","required":["chunkCount","entities","relationCount"],"properties":{"chunkCount":{"type":"integer"},"entities":{"type":"array","description":"Canonical live concepts this doc contributed mentions to, top by mentionCount, capped at 50.","items":{"type":"object","required":["id","name","type","authority","lifecycleStatus","mentionCount"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"authority":{"type":"string","enum":["machine_extracted","asserted","curated","certified"]},"lifecycleStatus":{"type":"string","enum":["draft","pending_review","published","deprecated","superseded"]},"mentionCount":{"type":"integer"}}}},"relationCount":{"type":"integer","description":"Live relations whose evidence cites this doc."}}},"downstream":{"type":"object","description":"Impact if the document changed (LENS + governance).","required":["citedByAnswers","cachedAnswers","impactedEntities"],"properties":{"citedByAnswers":{"type":"integer","description":"Persisted assistant messages whose [Sn] sources include this doc."},"cachedAnswers":{"type":"array","description":"Semantic-cache entries depending on this doc (capped at 50).","items":{"type":"object","required":["entryId","question","invalidated"],"properties":{"entryId":{"type":"string"},"question":{"type":"string"},"invalidated":{"type":"boolean","description":"True when the cache entry has been tombstoned."}}}},"impactedEntities":{"type":"integer","description":"Live entities grounded on this doc — the blast radius if deprecated/deleted."}}}}},"SearchResult":{"type":"object","description":"One retrieved chunk in a search response.","required":["chunkId","docId","docTitle","docPath","snippet","score","channels"],"properties":{"chunkId":{"type":"string"},"docId":{"type":"string"},"docTitle":{"type":"string"},"docPath":{"type":"string"},"headingPath":{"type":"string","description":"Heading breadcrumb of the chunk."},"snippet":{"type":"string","description":"First ~240 characters of the chunk."},"score":{"type":"number","description":"Reciprocal-rank-fused relevance score."},"channels":{"type":"array","items":{"type":"string"},"description":"Which retrieval channels matched, e.g. [\"fts\",\"vector\"]."},"rerankScore":{"type":"number","description":"Cross-encoder relevance in [0,1]. Present only when `?rerank=true` was requested AND a reranker actually ran; absent on raw retrieval or when reranking degraded to the fused order."}}},"SearchResponse":{"type":"object","required":["query","results","total"],"properties":{"query":{"type":"string","description":"The (trimmed) query that was run."},"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"total":{"type":"integer"}}},"DataConnector":{"type":"object","description":"A credential-masked data connector. The ciphertext is never returned.","required":["id","name","kind","enabled","hasCredential"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Adapter kind, e.g. \"postgres\", \"mysql\", \"snowflake\"."},"enabled":{"type":"boolean"},"hasCredential":{"type":"boolean","description":"Whether a secret is stored for this connector."}}},"DataConnectorList":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DataConnector"}},"total":{"type":"integer"}}},"DataQuery":{"type":"object","description":"A governed named query (SELECT/WITH-only template with typed params).","required":["id","slug","connectorId","enabled"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"connectorId":{"type":"string"},"enabled":{"type":"boolean"}}},"DataQueryList":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DataQuery"}},"total":{"type":"integer"}}},"DataRunResult":{"type":"object","description":"The result of a governed query execution with its provenance anchor. `dataCallId` is the persisted data_calls row (the [Dn] citation).","required":["dataCallId","connectorId","columns","rows","rowCount","durationMs","truncated"],"properties":{"dataCallId":{"type":"string","description":"Persisted data_calls provenance row id."},"connectorId":{"type":"string"},"queryId":{"type":["string","null"]},"columns":{"type":"array","items":{"type":"string"}},"rows":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Result rows as column→value objects."},"rowCount":{"type":"integer"},"durationMs":{"type":"integer"},"truncated":{"type":"boolean","description":"True when the connector's row cap was hit."}}},"Report":{"type":"object","description":"A report snapshot row. The full read additionally carries coverage + summary jsonb bodies.","required":["id","title","kind","status","generatedAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"kind":{"type":"string","enum":["engagement","coverage"]},"status":{"type":"string","enum":["ready","archived"]},"layoutVersion":{"type":["integer","null"]},"createdBy":{"type":["string","null"]},"generatedAt":{"type":"string","format":"date-time"}}},"ReportList":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"total":{"type":"integer"}}},"Citation":{"type":"object","description":"A knowledge-base citation attached to agent output.","required":["docId"],"properties":{"docId":{"type":"string"},"chunkId":{"type":"string"}}},"RunResult":{"description":"Terminal result of a run invocation: either a finished run (with text and citations) or a suspension awaiting human approval.","oneOf":[{"type":"object","title":"Finished","required":["runId","status","text","citations"],"properties":{"runId":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed","budget_exceeded","interrupted"]},"text":{"type":"string","description":"The agent's final output text."},"citations":{"type":"array","items":{"$ref":"#/components/schemas/Citation"}}}},{"type":"object","title":"Suspended","required":["runId","status","approvalId"],"properties":{"runId":{"type":"string"},"status":{"type":"string","const":"suspended"},"approvalId":{"type":"string","description":"Pass to POST /api/v1/runs/{id}/approve to resume."}}}]},"RunEvent":{"description":"One JSON-encoded SSE payload from POST /api/v1/agents/{slug}/runs (stream mode). Server-Sent Events stream (the default, `stream: true`). Each `data:` line is one JSON-encoded RunEvent. Intermediate `model_call` / `tool_call` events arrive as the run progresses; the stream then ends with exactly one terminal event: `final` (with status succeeded | failed | budget_exceeded | interrupted, the answer text, and citations), `suspended` (a tool call awaits human approval — resume via POST /api/v1/runs/{id}/approve), or `error` (including `no-model-configured`, which in stream mode arrives as an error event over a 200 response rather than a 409).","oneOf":[{"type":"object","title":"model_call","required":["type","runId","textLength","toolCalls"],"properties":{"type":{"type":"string","const":"model_call"},"runId":{"type":"string"},"textLength":{"type":"integer","description":"Characters of text produced by this model step."},"toolCalls":{"type":"integer","description":"Tool calls requested by this model step."}}},{"type":"object","title":"tool_call","required":["type","runId","name","ok"],"properties":{"type":{"type":"string","const":"tool_call"},"runId":{"type":"string"},"name":{"type":"string"},"ok":{"type":"boolean"}}},{"type":"object","title":"suspended (terminal)","required":["type","runId","approvalId"],"properties":{"type":{"type":"string","const":"suspended"},"runId":{"type":"string"},"approvalId":{"type":"string"},"toolName":{"type":"string","description":"The tool call awaiting approval."}}},{"type":"object","title":"final (terminal)","required":["type","runId","status","text","citations"],"properties":{"type":{"type":"string","const":"final"},"runId":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed","budget_exceeded","interrupted"]},"text":{"type":"string"},"citations":{"type":"array","items":{"$ref":"#/components/schemas/Citation"}}}},{"type":"object","title":"error (terminal)","required":["type","message"],"properties":{"type":{"type":"string","const":"error"},"message":{"type":"string","description":"Error message; \"no-model-configured\" when the workspace has no chat model."}}}]},"Run":{"type":"object","description":"A persisted agent run row. Timestamps are ISO 8601 strings; costUsd is a decimal string. input/output are JSON payloads whose shape depends on the agent.","required":["id","workspaceId","agentVersionId","status","trigger","tokensIn","tokensOut","costUsd","startedAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"agentVersionId":{"type":"string"},"conversationId":{"type":["string","null"]},"status":{"type":"string","enum":["running","suspended","idle","succeeded","failed","interrupted","budget_exceeded"]},"trigger":{"type":"string","enum":["ui","api","eval","schedule"]},"input":{"description":"The run's input payload (JSON)."},"output":{"description":"The run's output payload (JSON); null until finished."},"error":{"type":["string","null"]},"tokensIn":{"type":"integer"},"tokensOut":{"type":"integer"},"costUsd":{"type":"string","description":"Decimal string, e.g. \"0.031200\"."},"resumeCursor":{"description":"Internal durable-resume state; opaque to API consumers."},"heartbeatAt":{"type":["string","null"],"format":"date-time"},"apiKeyId":{"type":["string","null"],"description":"Set when the run was started via API key."},"configSnapshotId":{"type":["string","null"]},"evalResultId":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"startedAt":{"type":"string","format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"}}},"RunStep":{"type":"object","description":"One persisted step in a run's trace, ordered by idx.","required":["id","workspaceId","runId","idx","kind","tokensIn","tokensOut","costUsd","status","createdAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"runId":{"type":"string"},"idx":{"type":"integer"},"kind":{"type":"string","enum":["model_call","tool_call","mcp_call","guardrail","approval","retry"]},"name":{"type":["string","null"],"description":"Tool/guardrail name when applicable."},"input":{"description":"Step input payload (JSON)."},"output":{"description":"Step output payload (JSON)."},"modelId":{"type":["string","null"]},"tokensIn":{"type":"integer"},"tokensOut":{"type":"integer"},"costUsd":{"type":"string"},"latencyMs":{"type":["integer","null"]},"status":{"type":"string","enum":["ok","error","blocked","pending"]},"createdAt":{"type":"string","format":"date-time"}}}}},"servers":[{"url":"https://www.eli.ai","description":"This deployment"}]}