{"openapi":"3.1.0","info":{"title":"AgentDrive","description":"AgentDrive is an agent-focused artifact store: upload by path, share by rendered URL, address by stable permalink. The REST surface is documented here; the rendered viewer + agent claim flow live under `agentdrive.run`.","version":"0.0.1"},"servers":[{"url":"https://api.agentdrive.run","description":"Production"},{"url":"http://127.0.0.1:8000","description":"Local dev"}],"paths":{"/v0/artifacts/{path}":{"put":{"summary":"Upload (or overwrite) an artifact","description":"Upload an artifact at the given path. The path is treated as the artifact's location in the drive — re-uploading the same path overwrites in place (idempotent).\n\n**Limits:** request body must not exceed **50 MB**. Path must be non-empty, ≤256 chars, only `[A-Za-z0-9_./-]`, no `..` segments, no leading/trailing slash. Per-token write rate limit: 100/hour.\n\n**Optional headers.** Each preserves the existing artifact's value when omitted on an overwrite, and takes the create-default on a new path; send the header to replace it:\n- `X-AgentDrive-Labels`: comma-separated labels (e.g. `draft,report`); an empty value clears them. Each: lowercase `[a-z0-9_-]+`, ≤64 chars; ≤16 labels per artifact.\n- `X-AgentDrive-Metadata`: JSON object of agent-attached fields.\n- `X-AgentDrive-Source`: JSON `{\"refs\": [...]}` source provenance (present, including `{\"refs\": []}`, replaces).\n- `X-AgentDrive-Actor`: caller-supplied actor name (≤64 chars) for event-log attribution. Untrusted; never used for authz.","operationId":"put_artifact_v0_artifacts__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"content-type","in":"header","required":false,"schema":{"type":"string","default":"application/octet-stream","title":"Content-Type"}},{"name":"x-agentdrive-labels","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Labels"}},{"name":"x-agentdrive-metadata","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Metadata"}},{"name":"x-agentdrive-source","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Source"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"x-agentdrive-change-summary","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Change-Summary"}},{"name":"if-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-Match"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Artifact","operationId":"delete_artifact_v0_artifacts__path__delete","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"if-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-Match"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}":{"get":{"summary":"Canonical lookup of an artifact by its stable ID","operationId":"get_artifact_by_id_v0_artifacts__art_id__get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Rename / move an artifact to a new path","description":"Move the artifact to a new path on the same drive. ID, version history, source refs, labels, metadata, and the underlying CAS blob are preserved — only `path` and `updated_at` change.\n\nReturns 409 PATH_CONFLICT if the target path is already taken. Use `X-AgentDrive-Actor` to attach attribution to the emitted `artifact.renamed` event.","operationId":"rename_artifact_route_v0_artifacts__art_id__patch","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"if-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-Match"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Soft-delete an artifact by its stable ID","description":"Soft-delete the artifact with this `art_…` ID. Same semantics + response shape as the path-based `DELETE /v0/artifacts/{path}` (reversible until the GC cron hard-deletes at `purge_at`; `restore_url` points at the by-id restore), but keys on the immutable id so a concurrent rename can't change the target.\n\nReturns 404 ARTIFACT_NOT_FOUND if no live artifact has this id; 403 WIKI_RESERVED for `_wiki/` artifacts (system-managed); 412 if `If-Match` doesn't match the current version. Declared before the `{path:path}` family so the id convertor wins for DELETEs.","operationId":"delete_artifact_by_id_route_v0_artifacts__art_id__delete","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"if-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-Match"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/meta":{"get":{"summary":"Artifact metadata by stable ID (same shape as path /meta)","operationId":"get_artifact_by_id_meta_v0_artifacts__art_id__meta_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/copy":{"post":{"summary":"Duplicate an artifact to a new path (CAS-shared, new ID)","description":"Create a new artifact at `path` whose bytes are identical to the source artifact's. The copy reuses the source's CAS object (zero new storage) but gets a fresh `art_…` ID, a fresh version 1, and — by default — `source.refs = [{type: 'artifact', id: '<source>'}]` so provenance is preserved.\n\nQuota: the copy's `size_bytes` is added to the drive's `storage_bytes` even though physical bytes are shared.\n\nReturns 409 PATH_CONFLICT if the target path is already taken; 413 STORAGE_QUOTA_EXCEEDED if the copy would push the drive over its limit.","operationId":"copy_artifact_route_v0_artifacts__art_id__copy_post","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/download":{"get":{"summary":"Stream the artifact bytes by stable ID (never rendered HTML)","operationId":"download_artifact_by_id_v0_artifacts__art_id__download_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/versions":{"get":{"summary":"List versions of an artifact, newest first","description":"Returns versions in descending `version_number` order. Cursor pagination via `?cursor=<token>`; `next_cursor` is non-null when the page is full and more older versions may exist.","operationId":"list_artifact_versions_v0_artifacts__art_id__versions_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/versions/{version_number}":{"get":{"summary":"Metadata for a specific version of an artifact","operationId":"get_artifact_version_v0_artifacts__art_id__versions__version_number__get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"version_number","in":"path","required":true,"schema":{"type":"integer","title":"Version Number"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/versions/{version_number}/download":{"get":{"summary":"Stream bytes for a specific version (machine surface)","operationId":"download_artifact_version_v0_artifacts__art_id__versions__version_number__download_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"version_number","in":"path","required":true,"schema":{"type":"integer","title":"Version Number"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/download-url":{"get":{"summary":"Signed direct-from-GCS download URL by stable ID","description":"Returns a URL for the artifact's bytes. For large artifacts (>= the signed-download threshold) when signing is available, it's a short-lived **signed GCS URL** the client fetches directly (`direct:true`, `expires_at` set); otherwise the **proxy** `/download` URL (`direct:false`). Treat the URL as opaque. large-download-design.md §5.1.","operationId":"download_url_by_id_v0_artifacts__art_id__download_url_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadUrlOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/versions/{version_number}/download-url":{"get":{"summary":"Signed direct-from-GCS download URL for a specific version","description":"Same as `/{art_id}/download-url` but for a specific version's bytes (`direct:true` signed GCS URL when large + signing available, else the proxy `/versions/{n}/download` URL). large-download-design.md §5.1.","operationId":"download_url_version_v0_artifacts__art_id__versions__version_number__download_url_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"version_number","in":"path","required":true,"schema":{"type":"integer","title":"Version Number"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadUrlOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{path}/download-url":{"get":{"summary":"Signed direct-from-GCS download URL by path","description":"Same as `/{art_id}/download-url` but resolves the artifact by path. The returned proxy URL (when `direct:false`) still points at the by-id `/download` endpoint. large-download-design.md §5.1.","operationId":"download_url_by_path_v0_artifacts__path__download_url_get","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadUrlOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{path}/meta":{"get":{"summary":"Get Artifact Meta","operationId":"get_artifact_meta_v0_artifacts__path__meta_get","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts/{art_id}/restore":{"post":{"summary":"Restore a soft-deleted artifact","description":"Clear `deleted_at` + `purge_at` on a soft-deleted artifact. Available only while the artifact is in trash (i.e. before the GC cleanup cron purges it). Returns 404 if the artifact is live or already hard-deleted; 409 PATH_OCCUPIED if its path is now occupied by another live artifact. The 409 payload includes a `restore_options` block with `rename_to` and `force_overwrite` URLs the caller can follow to resolve the conflict — see deletion-design.md §5.4.","operationId":"restore_artifact_v0_artifacts__art_id__restore_post","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}},{"name":"rename","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Restore at this path instead of the original. Soft-deletes the live occupant at the original path with audit `metadata.cause='restore_conflict_rename'`. Mutually exclusive with `overwrite`.","title":"Rename"},"description":"Restore at this path instead of the original. Soft-deletes the live occupant at the original path with audit `metadata.cause='restore_conflict_rename'`. Mutually exclusive with `overwrite`."},{"name":"overwrite","in":"query","required":false,"schema":{"type":"boolean","description":"Soft-delete the live occupant at the original path and restore there. Audit `metadata.cause='restore_conflict_overwrite'`. Mutually exclusive with `rename`.","default":false,"title":"Overwrite"},"description":"Soft-delete the live occupant at the original path and restore there. Audit `metadata.cause='restore_conflict_overwrite'`. Mutually exclusive with `rename`."},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/drives/{drive_id}":{"delete":{"summary":"Soft-delete the authenticated drive","description":"Mark the drive for cleanup. All tenant data (artifacts, versions, wiki, embeddings, events) is hidden via the `live_*` views and CASCADE-removed by the GC cleanup cron at `purge_at`. Restore via `POST /v0/drives/{id}/restore` while the row is still in trash. The path-param `drive_id` MUST match the authenticated drive.","operationId":"delete_drive_route_v0_drives__drive_id__delete","parameters":[{"name":"drive_id","in":"path","required":true,"schema":{"type":"string","title":"Drive Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/drives/{drive_id}/restore":{"post":{"summary":"Restore a soft-deleted drive","description":"Clear `deleted_at` + `purge_at` on a soft-deleted drive. Soft-deleted child artifacts get their retention window rebased to the drive-restore moment (see deletion-design.md §5.2). Available only while the drive is in trash. Returns 404 if the drive is live or already hard-deleted.","operationId":"restore_drive_route_v0_drives__drive_id__restore_post","parameters":[{"name":"drive_id","in":"path","required":true,"schema":{"type":"string","title":"Drive Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/drives/{drive_id}/trash":{"get":{"summary":"List the authenticated drive's trash","description":"Returns soft-deleted artifacts on the drive plus the drive's own soft-delete state (if applicable). The path-param `drive_id` MUST match the authenticated drive.","operationId":"list_trash_route_v0_drives__drive_id__trash_get","parameters":[{"name":"drive_id","in":"path","required":true,"schema":{"type":"string","title":"Drive Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/artifacts":{"get":{"summary":"List artifacts in the drive","description":"Returns artifacts sorted by path. Filter by `prefix`, `label` (repeatable + AND-combined), and `file_type`.\n\n**Cursor pagination:** when more results exist, the response carries `next_cursor`. Pass it back as `?cursor=<token>` to fetch the next page. `next_cursor` is `null` on the final page. Filters MUST stay consistent across pages — the cursor encodes only the keyset position, not the filter set, so the client is responsible for re-sending the same filter on each page.","operationId":"list_artifacts_v0_artifacts_get","parameters":[{"name":"prefix","in":"query","required":false,"schema":{"type":"string","default":"","title":"Prefix"}},{"name":"label","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Label"}},{"name":"file_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/search":{"get":{"summary":"Full-text search over artifacts in the drive","description":"Lexical (not semantic) full-text search powered by Postgres `websearch_to_tsquery`. Results are ranked by `ts_rank` over a weighted tsvector (path > content > metadata > labels).\n\n**Supported query syntax:**\n- Words: `kangaroo` (English stemming)\n- Phrases: `\"exact phrase\"`\n- Negation: `kangaroo -secret`\n- AND (implicit): `kangaroo secret`\n- OR: `kangaroo OR koala`\n- Paths & filenames: `reports/q3-summary.md` or `q3-summary.md` match by their path words (`/ . _ -` are word boundaries)\n\n**Not supported (v0):**\n- Semantic / embedding similarity\n- PDF and image content (only the path + metadata are searchable)\n- Non-English stemming\n- Fuzzy matching, regex\n- Boolean operator parentheses\n\n**Filters:** `label` (repeatable, AND), `file_type` (enum), `prefix` (path prefix), `updated_after` / `updated_before` (RFC 3339 timestamps, inclusive bounds on `updated_at`).","operationId":"search_v0_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"title":"Q"}},{"name":"label","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Label"}},{"name":"file_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type"}},{"name":"prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefix"}},{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated After"}},{"name":"updated_before","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated Before"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/find":{"get":{"summary":"Hybrid passage retrieval over the full file body","description":"Passage-level chunk RAG over `embed_chunks`. Lexical (`chunk_tsv`, GIN) + semantic (HNSW over `embedding`) are run in parallel and fused via Reciprocal Rank Fusion (k=60). Unlike `/v0/search`, which only sees the first ~16 KB preview of each artifact, `/v0/find` reaches the full file body.\n\n**Modes:**\n- `hybrid` (default) — lexical + semantic, RRF-fused.\n- `lexical` — `chunk_tsv` only. Best for exact tokens, identifiers, code snippets.\n- `semantic` — embedding only. Best for conceptual queries where the surface terms differ from the query phrasing.\n\n**Granularity:** results are passages, not files. A long document with multiple matching regions returns multiple hits with distinct `ord` values; consecutive `ord`s overlap by ~400 tokens. Dedupe by `art_id` if you want one row per file.\n\n**Span citations:** `char_start`/`char_end` for text & code, `page_start`/`page_end` for PDFs, `time_start_ms`/`time_end_ms` for audio & video. Only the modality-relevant pair is populated.\n\n**Filters:** `label`, `file_type`, `prefix`, `modality` (repeatable), `updated_after` / `updated_before` (RFC 3339 timestamps, inclusive bounds on `updated_at`, applied to both legs).\n\n**Wiki coverage:** `/v0/find` excludes `_wiki/` paths by default and — importantly — does NOT cover them even when the caller passes `prefix=_wiki/...`. Wiki pages are not embedded by the pipeline (they're system-generated output, not user input), so `embed_chunks` has no rows for them and the join returns empty. Use `wiki_search` (or `list`/`grep` with a `_wiki/` prefix) for the wiki layer.\n\n**Embedding availability:** when `GEMINI_API_KEY` is not configured, `mode=semantic` returns 500; `mode=hybrid` logs a warning and falls back to lexical-only; `mode=lexical` is unaffected.","operationId":"find_v0_find_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":500,"title":"Q"}},{"name":"mode","in":"query","required":false,"schema":{"enum":["hybrid","lexical","semantic"],"type":"string","default":"hybrid","title":"Mode"}},{"name":"label","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Label"}},{"name":"file_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type"}},{"name":"prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefix"}},{"name":"modality","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Modality"}},{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated After"}},{"name":"updated_before","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated Before"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{fld_id}":{"get":{"summary":"Canonical lookup of a folder by its stable ID","operationId":"get_folder_by_id_v0_folders__fld_id__get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Update folder metadata by stable ID","operationId":"patch_folder_by_id_v0_folders__fld_id__patch","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Soft-delete a folder by stable ID (cascade with ?recursive=true)","operationId":"delete_folder_by_id_v0_folders__fld_id__delete","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"recursive","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Recursive"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderDeleteOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{fld_id}/meta":{"get":{"summary":"Folder metadata by stable ID (same shape as the bare id route)","operationId":"get_folder_by_id_meta_v0_folders__fld_id__meta_get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{fld_id}/move":{"post":{"summary":"Rename / move a folder by stable ID (cascade descendants)","operationId":"move_folder_by_id_v0_folders__fld_id__move_post","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderMoveIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{path}/move":{"post":{"summary":"Rename / move a folder (cascade-update descendants)","description":"Move the folder identified by URL path to the body's `path`. All descendant folders + artifacts are path-prefix-updated in the same transaction. The folder's `fld_*` ID stays stable.\n\nReturns 409 `FOLDER_PATH_CONFLICT` if the destination prefix collides with a live folder or artifact path.","operationId":"move_folder_by_path_v0_folders__path__move_post","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderMoveIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{path}":{"post":{"summary":"Create a folder (idempotent)","description":"Create a folder at the URL path. Idempotent — a second call for the same live path returns the existing row unchanged (metadata updates require PATCH).\n\nReturns 409 `FOLDER_PATH_CONFLICT` if a live artifact occupies the file form of the path (e.g. mkdir `/foo/` when an artifact lives at `/foo`).","operationId":"create_folder_by_path_v0_folders__path__post","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/FolderCreateIn"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Read folder metadata by path","operationId":"get_folder_by_path_v0_folders__path__get","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Update folder metadata by path","description":"Partial update — field absence leaves the value unchanged; explicit `null` clears the field. Use the by-id endpoint (slice 2) when you need stable addressing across renames.","operationId":"patch_folder_by_path_v0_folders__path__patch","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Soft-delete a folder (cascade with ?recursive=true)","description":"Soft-delete the folder. Refuses if the folder has live descendants unless `?recursive=true` is set, in which case ALL descendant folders + artifacts are soft-deleted in the same transaction.\n\nReturns 409 `FOLDER_RECURSIVE_REQUIRED` (with descendant counts in `colliding_path`) when recursion is needed but the flag isn't set. Retention window is frozen on `purge_at` per deletion-design.md §5.1; mid-retention tier changes don't shift it.","operationId":"delete_folder_by_path_v0_folders__path__delete","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"recursive","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Recursive"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderDeleteOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/folders/{path}/meta":{"get":{"summary":"Folder metadata by path (same shape as the bare path route)","operationId":"get_folder_by_path_meta_v0_folders__path__meta_get","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/events":{"get":{"summary":"Read the append-only event log for the authenticated drive","description":"Returns events newest-first. Filters compose with AND.\n\n**Cursor pagination:** pass the oldest event's `created_at` from the previous page as `before` to fetch the next page back in time. Combine `since` + `before` to bound a window.","operationId":"list_events_route_v0_events_get","parameters":[{"name":"art_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Art Id"}},{"name":"action","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Since"}},{"name":"before","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Before"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/drives/me":{"get":{"summary":"Me","description":"Drive overview for the authenticated bearer token.\n\nWire-protocol preservation (WorkOS integration §6): the `email` field\nis preserved in the response shape; its meaning is now \"the drive's\nowner's email\" (via `drives.owner_user_id` → `users.email`, joined\nin `auth.resolve_drive`). For solo signups this equals v0 behavior —\nthe email the user signed up with. Returns null if the owner has\nbeen hard-purged. `organization_id` is a new additive field.","operationId":"me_v0_drives_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/drives/me/usage":{"get":{"summary":"Current-period usage + caps for the authenticated drive","description":"Unified view of every metered dimension: storage (snapshot), writes (current hour), indexing ops + retrieval queries (current calendar month UTC). Each row carries `used` and `limit`; `limit: 0` means unlimited (the v0 free-tier default for the two monthly counters). Reads are de-throttled — there is no hourly read budget; the monthly read count appears under `ops_this_month.reads`.","operationId":"me_usage_v0_drives_me_usage_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/feedback":{"post":{"summary":"Post Feedback","description":"File feedback. Body: `{kind, title, body, contact?,\nattachments?: [art_id, ...]}` — attachments are snapshotted from\nthis drive's artifacts at submit time.","operationId":"post_feedback_v0_feedback_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/feedback/{fbk_id}":{"get":{"summary":"Get Feedback Status","description":"Lifecycle status of feedback THIS drive filed. Foreign tickets\nread as 404 — indistinguishable from absent.","operationId":"get_feedback_status_v0_feedback__fbk_id__get","parameters":[{"name":"fbk_id","in":"path","required":true,"schema":{"type":"string","title":"Fbk Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/grants":{"post":{"summary":"Create (or fetch) a per-principal grant on a resource","operationId":"create_grant_route_v0_grants_post","parameters":[{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List live grants on a resource (requires can_manage)","operationId":"list_grants_route_v0_grants_get","parameters":[{"name":"resource","in":"query","required":true,"schema":{"type":"string","description":"art_*/fld_* id or a path","title":"Resource"},"description":"art_*/fld_* id or a path"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/grants/{grn_id}":{"patch":{"summary":"Update a grant's role and/or expiry (requires can_manage)","operationId":"patch_grant_route_v0_grants__grn_id__patch","parameters":[{"name":"grn_id","in":"path","required":true,"schema":{"type":"string","title":"Grn Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Revoke a grant (can_manage, or self-revoke own grant)","operationId":"delete_grant_route_v0_grants__grn_id__delete","parameters":[{"name":"grn_id","in":"path","required":true,"schema":{"type":"string","title":"Grn Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/shares":{"post":{"summary":"Mint a share link (returns the share_key once)","operationId":"create_share_route_v0_shares_post","parameters":[{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareMintOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List live share links on a resource (requires can_manage)","operationId":"list_shares_route_v0_shares_get","parameters":[{"name":"resource","in":"query","required":true,"schema":{"type":"string","description":"art_*/fld_* id or a path","title":"Resource"},"description":"art_*/fld_* id or a path"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/shares/{shr_id}":{"delete":{"summary":"Revoke a share link (requires can_manage)","operationId":"delete_share_route_v0_shares__shr_id__delete","parameters":[{"name":"shr_id","in":"path","required":true,"schema":{"type":"string","title":"Shr Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/shares/{shr_id}/rotate":{"post":{"summary":"Revoke + reissue a share link's key (requires can_share)","operationId":"rotate_share_route_v0_shares__shr_id__rotate_post","parameters":[{"name":"shr_id","in":"path","required":true,"schema":{"type":"string","title":"Shr Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareMintOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/upload/{token}":{"put":{"summary":"Proxied streaming upload (via an upload_url token)","description":"Streams an artifact body into AgentDrive using a single-use token that was previously minted by the `upload_url` MCP tool. The token encodes the artifact path, content type, size cap, labels, metadata, source, actor, change summary, and `if_match` — all frozen at mint time. The request carries only the raw bytes + a `Content-Type` header that must match the signed value.\n\n**Auth.** No Authorization header — the token in the path is the credential.\n\n**Single-use.** Replay returns 409 TOKEN_REPLAYED. Expiry returns 401 TOKEN_EXPIRED. Bodies exceeding the signed cap return 413 BYTES_LIMIT.","operationId":"stream_upload_v0_upload__token__put","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"400":{"description":"Content-Type mismatch or other validation failure"},"401":{"description":"Token invalid / expired / drive deleted"},"403":{"description":"Path reserved for the system (WIKI_RESERVED)"},"409":{"description":"Token already consumed (replay)"},"412":{"description":"If-Match precondition failed"},"413":{"description":"Body exceeded signed max_bytes or drive quota"},"429":{"description":"Drive's per-hour write budget exhausted"},"503":{"description":"Storage backend unavailable (STORAGE_FAILURE)"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/uploads":{"post":{"summary":"Begin a large (direct-to-GCS) upload","description":"Reserve quota and open a resumable upload session for a file larger than the buffered-upload limit. Returns a `upload_url` to PUT the raw bytes to DIRECTLY (no Authorization header — the URL is the credential), then call `/v0/uploads/{upload_id}/commit`. All artifact decisions (path, labels, metadata, source, if_match) are frozen here.","operationId":"begin_upload_v0_uploads_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBeginIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBeginOut"}}}},"400":{"description":"Invalid path / labels / metadata / source"},"402":{"description":"Drive storage quota would be exceeded"},"403":{"description":"Path reserved for the system (WIKI_RESERVED)"},"413":{"description":"size_bytes exceeds the drive's per-artifact cap"},"429":{"description":"Drive's per-hour write budget exhausted"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/uploads/{upload_id}/commit":{"post":{"summary":"Commit a large (direct-to-GCS) upload","description":"Finalize the upload begun at `/v0/uploads`: AgentDrive verifies the object that landed in GCS (size + checksum) and creates the artifact. Idempotent — a retry after a successful commit returns the same artifact. The write budget is charged here (begin is free metadata).","operationId":"commit_upload_v0_uploads__upload_id__commit_post","parameters":[{"name":"upload_id","in":"path","required":true,"schema":{"type":"string","title":"Upload Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOut"}}}},"404":{"description":"No such upload for this drive"},"409":{"description":"Uploaded object size != declared size_bytes"},"410":{"description":"Upload session expired"},"412":{"description":"If-Match precondition failed"},"429":{"description":"Drive's per-hour write budget exhausted"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/projects/{fld_id}/jobs":{"post":{"summary":"Enqueue a compile job for a project (folder)","operationId":"enqueue_job_v0_projects__fld_id__jobs_post","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"x-agentdrive-actor","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Agentdrive-Actor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompileJobIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List a project's jobs","operationId":"list_project_jobs_v0_projects__fld_id__jobs_get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/jobs/{job_id}":{"get":{"summary":"Poll a job","operationId":"get_job_v0_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/jobs/{job_id}/logs":{"get":{"summary":"Raw compile log (text/plain)","operationId":"get_job_logs_v0_jobs__job_id__logs_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/jobs/{job_id}/cancel":{"post":{"summary":"Cancel a queued/running job","operationId":"cancel_job_v0_jobs__job_id__cancel_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/projects/{fld_id}":{"put":{"summary":"Set a project's compile config (entrypoint/engine/auto_compile)","operationId":"put_project_v0_projects__fld_id__put","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectConfigIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Get a project's compile config","operationId":"get_project_v0_projects__fld_id__get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/jwks.json":{"get":{"tags":["agent-auth"],"summary":"JSON Web Key Set — public keys for verifying AgentDrive JWTs","description":"Public half of the RSA signing key for identity_assertion + access_token JWTs issued by AgentDrive. RFC 7517 shape. Cache-friendly; key rotation publishes both kids during the overlap window.","operationId":"jwks__well_known_jwks_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Jwks  Well Known Jwks Json Get"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"tags":["agent-auth"],"summary":"Protected-resource metadata (auth.md / RFC 9728-like discovery)","description":"Names this server as a protected resource and points clients at the authorization server they should obtain tokens from. In this design the resource server and authorization server are the same host.","operationId":"oauth_protected_resource__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Oauth Protected Resource  Well Known Oauth Protected Resource Get"}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"tags":["agent-auth"],"summary":"Protected-resource metadata for the MCP endpoint (RFC 9728 §3.1)","description":"Path-inserted variant of the protected-resource document. MCP clients derive this URL from the resource URL `{origin}/mcp` (RFC 9728 §3.1: insert the well-known segment between host and path) after reading the WWW-Authenticate challenge on a 401 — it is the first hop of the client-side OAuth flow.","operationId":"oauth_protected_resource_mcp__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Oauth Protected Resource Mcp  Well Known Oauth Protected Resource Mcp Get"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["agent-auth"],"summary":"Authorization-server metadata (RFC 8414 + auth.md agent_auth block)","description":"Discovery document for the auth.md protocol. Carries the standard RFC 8414 fields plus an `agent_auth` block per the auth.md spec — the latter is what an agent runtime keys off to find the identity + claim endpoints.","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Oauth Authorization Server  Well Known Oauth Authorization Server Get"}}}}}}},"/agent/identity":{"post":{"tags":["agent-auth"],"summary":"Register an agent identity (anonymous or ID-JAG)","description":"Two registration modes:\n\n**`type=anonymous`** — Provisions a brand-new agent identity bound to a fresh shadow-org drive. No human involved; returned `identity_assertion` carries `scope=pre_claim`. A human completes the claim ceremony later via /claim.\n\n**`type=identity_assertion`** — Agent provider (e.g. WorkOS) has already minted an ID-JAG asserting a user identity binding. We verify it against the provider's JWKS and provision a **claimed** identity immediately: scope=full, drive bound to the user, no claim ceremony needed.","operationId":"register_agent_identity_agent_identity_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnonymousIdentityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agent/identity/claim":{"post":{"tags":["agent-auth"],"summary":"Initiate the human-claim ceremony for an agent identity","description":"Returns a `user_code` and `verification_uri` (RFC 8628 device-code idiom). The agent surfaces these to the human, who visits the URI, signs in, and approves the claim. The agent then polls POST /oauth2/token (grant_type=claim) with the same `claim_token` to learn when the claim completes.","operationId":"initiate_claim_agent_identity_claim_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimInitRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimInitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth2/token":{"post":{"tags":["agent-auth"],"summary":"Exchange a credential for an access_token","description":"Two grant types:\n\n**`urn:ietf:params:oauth:grant-type:jwt-bearer`** (RFC 7523) — body `assertion=<identity_assertion JWT>`. Returns a fresh 15-minute access_token with the same scope as the assertion.\n\n**`claim`** (custom) — body `claim_token=<from POST /agent/identity>`. Polling endpoint for the claim ceremony. Returns one of: `authorization_pending` (400), `expired_token` (400), `access_denied` (400), or access_token + new identity_assertion + scope=full (200).","operationId":"oauth2_token_oauth2_token_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_oauth2_token_oauth2_token_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v0/auth/extension/exchange":{"post":{"tags":["agent-auth"],"summary":"Redeem an extension OAuth ticket for a JWT pair","description":"Single-use opaque ticket → JWT pair. Called once by an extension's auth-complete.html after the OAuth handoff lands. Returns a 15-minute `access_token` (scope=extension) and a 90-day `identity_assertion` the extension stores and refreshes via POST /oauth2/token.","operationId":"extension_exchange_v0_auth_extension_exchange_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtensionExchangeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtensionExchangeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth2/register":{"post":{"tags":["mcp-oauth"],"summary":"Dynamic Client Registration (RFC 7591)","description":"Anonymous registration endpoint for MCP clients. Public clients only (PKCE, no client_secret). Returns the registered metadata plus the assigned `client_id`. Registration grants nothing by itself — every token still requires a user consent ceremony at /oauth2/authorize.","operationId":"oauth2_register_oauth2_register_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth2/revoke":{"post":{"tags":["mcp-oauth"],"summary":"Token revocation (RFC 7009)","description":"Revokes an `adat_` access token (that token only) or an `adrt_` refresh token (the whole rotation chain). Unknown tokens return 200 per RFC 7009 §2.2 — existence is not revealed. Public-client endpoint auth (`client_id` form param, no secret).","operationId":"oauth2_revoke_oauth2_revoke_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/claim":{"get":{"tags":["claim-ui"],"summary":"Claim Page","description":"Three states, each rendered via the same template with a\ndifferent `state` discriminator. The user_code is read from the\nquery string so the URL is shareable from the agent's UI.\n\nAuth: WorkOS browser session required. If absent, redirect to\n`/auth/login?return_to=/claim?code=<code>` and the user lands\nback here after sign-in.","operationId":"claim_page_claim_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agent/identity/claim/complete":{"post":{"tags":["claim-ui"],"summary":"Claim Complete","description":"Browser-form submit from `/claim`. CSRF-gated +\nWorkOS-session-gated. Atomically binds the drive to the user OR\nmarks the attempt denied.\n\nSee design §5.3 for the algorithm — concurrency note: we\n`SELECT … FOR UPDATE` on the claim_attempts row to serialize the\ndouble-click case before running the drive_limit gate.","operationId":"claim_complete_agent_identity_claim_complete_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_claim_complete_agent_identity_claim_complete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth2/authorize":{"get":{"tags":["mcp-oauth-ui"],"summary":"Authorize Page","operationId":"authorize_page_oauth2_authorize_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["mcp-oauth-ui"],"summary":"Authorize Decision","operationId":"authorize_decision_oauth2_authorize_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_authorize_decision_oauth2_authorize_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/extension/start":{"get":{"summary":"Extension Start","description":"Begin a WorkOS sign-in flow on behalf of a Chrome extension.\n\nStamps `for=ext` + `ext_id` into the signed OAuth state so the\ncallback handler knows to render the extension handoff page\ninstead of setting a session cookie.\n\nThree short-circuits, all surface as actionable errors:\n  * EXTENSION_AUTH_DISABLED (503): kill switch flipped off.\n  * UNKNOWN_EXTENSION (400): `ext_id` not on the allow-list.\n  * Missing `ext_id` query string (400 INVALID_REQUEST).","operationId":"extension_start_auth_extension_start_get","parameters":[{"name":"ext_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"get":{"summary":"Login","description":"Begin a WorkOS sign-in flow.\n\nMints a pre-login state cookie (binds the OAuth flow to this\nbrowser — defense-in-depth against login-CSRF), signs a state\npayload, and redirects to AuthKit. The hosted AuthKit page lets\nthe user pick Google OAuth, Microsoft OAuth, magic-link,\npassword, or passkey; we don't care which — they all funnel\nback to /auth/callback with a `code` we exchange in D2.","operationId":"login_auth_login_get","parameters":[{"name":"return_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/callback":{"get":{"summary":"Callback","description":"Complete a sign-in.\n\nHandles the auth provider's OAuth callback and shapes failures into\nuser-readable errors:\n  * an invalid or expired login flow — LOGIN_FLOW_INVALID (400);\n  * an invalid or already-used authorization code — AUTH_CODE_INVALID (400);\n  * the upstream auth provider being unavailable — WORKOS_UNAVAILABLE (502),\n    returned with Retry-After.","operationId":"callback_auth_callback_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"summary":"Logout","description":"Terminate both the local session AND the upstream WorkOS session.\n\nWithout the WorkOS-side termination, the next `/auth/login` flow\nsilently re-authenticates the user through AuthKit's still-valid\nsession cookie on `api.workos.com` — \"Sign out\" feels broken and\na shared-browser user can't switch accounts. The recommended\npattern (per https://workos.com/docs/authkit/sessions) is to\nredirect to the WorkOS logout endpoint with the `sid` we stashed\nduring the callback; WorkOS clears its own session and returns\nthe browser to our `return_to`.\n\nFailure modes handled:\n  * No `workos_session_id` in the session (legacy v2 cookie issued\n    before this slice landed): fall back to local-only logout. The\n    upstream session lingers but the user's local state is cleared\n    — same UX as before this slice; cookie rotation on next sign-in\n    eventually overwrites it.\n  * SDK raises during `get_logout_url`: pure string formatting at\n    WorkOS's end, so the only realistic failure is a misconfigured\n    WorkOS dashboard (no Sign-out redirect registered). We catch\n    and fall back to local-only logout rather than 500ing — the\n    user clicked \"Sign out\", they should land somewhere, not on an\n    error page.","operationId":"logout_auth_logout_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_logout_auth_logout_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/recovery":{"get":{"summary":"Recovery Page","description":"Show the recover-or-start-fresh decision. Requires a valid\n`pending_recovery` payload — direct hits without one bounce to\n/auth/login (the recovery state is only meaningful inside the\ncallback → recovery → resolve chain).","operationId":"recovery_page_auth_recovery_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/recovery/restore":{"post":{"summary":"Recovery Restore","description":"Recover the soft-deleted account. Undelete cascade runs in\n`onboarding.recover_account`; on success we set the normal\nsession and bounce to /dashboard. If the retention window has\nlapsed between page-render and POST (the GC raced us), surface\nthe same \"expired\" redirect so the user lands somewhere\nactionable.","operationId":"recovery_restore_auth_recovery_restore_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_recovery_restore_auth_recovery_restore_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/recovery/new-account":{"post":{"summary":"Recovery New Account","description":"Start fresh under the same identity.\n\nProvisions a new user / org / drive; the soft-deleted record stays\nin trash until garbage-collected. Lands on /welcome so the user sees\nthe freshly-minted API key once.","operationId":"recovery_new_account_auth_recovery_new_account_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_recovery_new_account_auth_recovery_new_account_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/recovery/new-account-expired":{"get":{"summary":"Recovery New Account Expired","description":"Friendly landing for the rare race where the soft-deleted row\nhas been hard-purged between callback and recovery-page render.\nClears the recovery cookie (only when one is present) and tells\nthe user to retry — fresh sign-in will JIT-provision cleanly\nsince no soft-deleted record blocks it any more.\n\nGated on `pending_recovery` so a normal signed-in user who\nnavigates here directly doesn't get their session wiped. Without\na pending payload there's nothing to expire; bounce home.","operationId":"recovery_new_account_expired_auth_recovery_new_account_expired_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/web/artifacts/indexed":{"get":{"summary":"Web Artifact Indexed","description":"Session-auth companion to `/v0/artifacts/{path}/meta` used by the\nwiki-banner poller in the browser. The poller runs in any logged-in\nowner's tab; the v0 endpoint requires Bearer auth and was therefore\ndead for browser owners (the banner spinner never resolved).\n\nReturns `{indexed_at, has_index}` so the poller can detect when the\nextraction finishes and reload the page. 401 if not signed in (anon\nviewer); 404 if the path doesn't exist in the caller's drive.\n\nRate limit is generous (120/min) because the banner polls every 5s and\na user might leave multiple tabs open. Per-IP keying so one abusive\nclient doesn't starve out concurrent legit polls from other users.","operationId":"web_artifact_indexed_web_artifacts_indexed_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","maxLength":512,"title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/projects/{fld_id}/files":{"get":{"summary":"Web Project Files","description":"Cookie-authed file tree + read-only source manifest for the LaTeX\nworkspace (handoff §3). Same auth contract as the preview poll (401 /\n404-not-403). Source bytes themselves stream from `/a/{art_id}?raw=1`\n(owner session authorizes private files) — this endpoint only lists.","operationId":"web_project_files_web_projects__fld_id__files_get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/projects/{fld_id}/preview":{"get":{"summary":"Web Project Preview","description":"Session-auth poll for the live PDF preview page (latex-live-preview-\ndesign.md §4.2). The browser uses the session cookie (the `/v0` jobs API\nis Bearer-only), so this is the cookie-authed companion. Returns the\ncurrent compile status + the last successful PDF + diagnostics so the page\nupdates in place. 401 if not signed in; 404 (not 403) if the folder isn't\nin the caller's drive, to avoid existence leakage.","operationId":"web_project_preview_web_projects__fld_id__preview_get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/f/{fld_id}/preview":{"get":{"summary":"Project Preview Page","description":"Live PDF preview for a project folder (latex-live-preview-design.md).\n\nURL mirrors the folder permalink (`/f/{fld_id}` → dashboard;\n`/f/{fld_id}/preview` → live preview) and the editor (`/a/{art_id}/edit`).\nOwner-only focused viewer: the page polls `/web/projects/{fld_id}/preview`\nand re-renders the compiled PDF in place (PDF.js) as the agent recompiles.\nAnonymous / non-owner → bounce through login with this URL as return_to.\nThe page renders an empty shell; preview.js owns all behavior.","operationId":"project_preview_page_f__fld_id__preview_get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/artifacts/{path}":{"put":{"summary":"Web Put Artifact","description":"Cookie-authed write of an image artifact. Used by the SnipIt web\neditor (`/a/{art_id}/edit`) for autosave; the bearer-authed\n`PUT /v0/artifacts/{path}` won't accept a cookie-only session.\n\nOwner-only; the path is checked against the signed-in user's drive.\nAccepts `image/*` (SnipIt editor autosave) and `application/pdf` (the\nPDF viewer's annotation save) only — refuses everything else so the\neditor can't smuggle markdown/HTML or anything else through this surface.\nMirrors every guard the v0 PUT enforces — write quota, reserved\n`_wiki/` namespace rejection, per-tier max-bytes cap (both\n`Content-Length` short-circuit and post-body length check) — so\na logged-in user can't bypass quota or write into the wiki by\nrouting autosaves through this endpoint instead of the v0 API.\nCSRF is checked via the `X-CSRF-Token` header (see\n`csrf.require_csrf_header`); the editor reads the token from the\n`<meta name=\"csrf-token\">` tag rendered into the edit page.\nRate-limited per-IP/user at the same cadence the editor's 1.5s\nautosave can sustain without flagging abuse.","operationId":"web_put_artifact_web_artifacts__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Web Delete Artifact","description":"Cookie-authed delete used by the editor's Discard button\n(`/a/{art_id}/edit`): if the user isn't happy with a capture, they\ndelete it right there instead of round-tripping through the\ndashboard. The bearer-authed `DELETE /v0/artifacts/{path}` won't\naccept a cookie-only session, hence this `/web/...` alias — the\nsame split as the autosave PUT above.\n\nMirrors the v0 DELETE's guards: CSRF header (cross-site fetch\ncan't forge the token), write-quota consumption, and reserved\n`_wiki/` namespace rejection. Soft-delete semantics are identical\ntoo — the artifact lands in trash and is restorable until the GC\ncron purges it at `purge_at`, so a misclick through the confirm\ndialog is recoverable. `If-Match` is deliberately not supported:\nthe editor is the only intended caller and always deletes\nwhatever is current.\n\nNote: `restore_url` in the response points at the bearer-authed\nv0 endpoint, which this cookie-only caller can't hit — it's kept\nfor shape parity with the v0 DELETE and is informational here\n(a future web trash UI would need a `/web/...` restore alias).","operationId":"web_delete_artifact_web_artifacts__path__delete","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/a/{art_id}/edit":{"get":{"summary":"Edit Artifact","description":"SnipIt annotation editor for an image artifact.\n\nURL pattern mirrors the artifact permalink (`/a/{art_id}` → viewer;\n`/a/{art_id}/edit` → editor). FastAPI matches the more-specific\n`/edit` path before `/a/{art_id}` so there's no collision.\n\nOwner-only: requires a signed-in session cookie AND the artifact\nmust belong to the user's currently-active drive. Non-owners and\nanonymous viewers redirect to /auth/login with this URL as\n`return_to` so they land back here after sign-in.\n\nRenders an editor shell — the editor JS owns all behavior (load\nthe PNG, draw annotations on a canvas overlay, auto-save via\n`PUT /web/artifacts/{path}` with cookie auth). v0 supports image\nartifacts only; non-image art_ids redirect to the canonical\nviewer URL.\n\nPairs with the SnipIt Chrome extension: after auto-upload finishes\nthe extension's SW navigates the tab to this URL, so the user's\nURL bar shows the real `agentdrive.run/a/<art_id>/edit` instead\nof a chrome-extension://... page. Editing on the web app side\nalso means the same flow is reachable from the dashboard (\"Edit\nthis clip\") without the extension installed.","operationId":"edit_artifact_a__art_id__edit_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/trash":{"get":{"summary":"Trash","description":"Drive-wide Trash: soft-deleted artifacts + folder roots, each with\na Restore action. Restore wiring lives in web/file_ops.py.","operationId":"trash_web_trash_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard":{"get":{"summary":"Dashboard","operationId":"dashboard_dashboard_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"default":"","title":"Q"}},{"name":"path","in":"query","required":false,"schema":{"type":"string","maxLength":256,"default":"","title":"Path"}},{"name":"wiki","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Wiki"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","maxLength":32,"default":"","title":"Type"}},{"name":"label","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Label"}},{"name":"after","in":"query","required":false,"schema":{"type":"string","maxLength":64,"default":"","title":"After"}},{"name":"before","in":"query","required":false,"schema":{"type":"string","maxLength":64,"default":"","title":"Before"}},{"name":"view","in":"query","required":false,"schema":{"type":"string","maxLength":16,"default":"","title":"View"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","maxLength":16,"default":"","title":"Sort"}},{"name":"dir","in":"query","required":false,"schema":{"type":"string","maxLength":8,"default":"","title":"Dir"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/folders/new":{"post":{"summary":"Web New Folder","operationId":"web_new_folder_web_folders_new_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_new_folder_web_folders_new_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/upload":{"post":{"summary":"Web Upload","operationId":"web_upload_web_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_web_upload_web_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/artifacts/rename":{"post":{"summary":"Web Rename Artifact","operationId":"web_rename_artifact_web_artifacts_rename_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_rename_artifact_web_artifacts_rename_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/folders/move":{"post":{"summary":"Web Move Folder","operationId":"web_move_folder_web_folders_move_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_move_folder_web_folders_move_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/artifacts/copy":{"post":{"summary":"Web Copy Artifact","operationId":"web_copy_artifact_web_artifacts_copy_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_copy_artifact_web_artifacts_copy_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/artifacts/delete":{"post":{"summary":"Web Delete Artifact Op","operationId":"web_delete_artifact_op_web_artifacts_delete_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_delete_artifact_op_web_artifacts_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/folders/delete":{"post":{"summary":"Web Delete Folder","operationId":"web_delete_folder_web_folders_delete_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_delete_folder_web_folders_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/set":{"post":{"summary":"Web Set Metadata","description":"Folder description edit (target = `fld_<id>`).\n\n\"Public/private\" is no longer a folder/artifact flag — access is\nexpressed through grants (permission-sharing-design §4.4), so this\nendpoint only edits folder descriptions. Artifact targets are\nrejected; publishing an artifact is the dedicated grant/`publish`\nflow, not a metadata toggle.","operationId":"web_set_metadata_web_set_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_set_metadata_web_set_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/artifacts/restore":{"post":{"summary":"Web Restore Artifact","operationId":"web_restore_artifact_web_artifacts_restore_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_restore_artifact_web_artifacts_restore_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/projects/{fld_id}/compile":{"post":{"summary":"Web Project Compile","operationId":"web_project_compile_web_projects__fld_id__compile_post","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_project_compile_web_projects__fld_id__compile_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/folders/restore":{"post":{"summary":"Web Restore Folder","operationId":"web_restore_folder_web_folders_restore_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_web_restore_folder_web_folders_restore_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}":{"get":{"summary":"Get Share State","operationId":"get_share_state_web_share__rid__get","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/public":{"post":{"summary":"Set Public","description":"Toggle world-readable: create (idempotent) or revoke the `anyone:viewer`\ngrant. On a folder this cascades to the subtree (the response carries the\nblast-radius the UI confirmed).","operationId":"set_public_web_share__rid__public_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/grant":{"post":{"summary":"Add Grant","operationId":"add_grant_web_share__rid__grant_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/grant/{grn_id}/revoke":{"post":{"summary":"Revoke Grant","operationId":"revoke_grant_web_share__rid__grant__grn_id__revoke_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"grn_id","in":"path","required":true,"schema":{"type":"string","title":"Grn Id"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/seal":{"post":{"summary":"Set Seal","description":"Set the limited-access seal (`inherit_grants`). `false` makes the\nresource ignore grants inherited from ancestor folders (§4.6/§4.11).\nGated on `can_manage` (changing who can reach the resource).","operationId":"set_seal_web_share__rid__seal_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SealIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/link":{"post":{"summary":"Create Link","description":"Mint a viewer share link. Returns the fresh state PLUS `minted` with the\nraw `share_key` + url — the ONLY response that carries the key. Artifacts\nonly (v1: folder share links are not supported).","operationId":"create_link_web_share__rid__link_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/share/{rid}/link/{shr_id}/revoke":{"post":{"summary":"Revoke Link","operationId":"revoke_link_web_share__rid__link__shr_id__revoke_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"string","title":"Rid"}},{"name":"shr_id","in":"path","required":true,"schema":{"type":"string","title":"Shr Id"}},{"name":"x-csrf-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Csrf-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/settings":{"get":{"summary":"Settings Account","description":"Default settings landing — Account info + Danger zone.","operationId":"settings_account_settings_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/settings/api-keys":{"get":{"summary":"Settings Api Keys","description":"API key tab. Also where reveal_key is rendered after rotation; the\nreveal is consumed (removed from session) on first read.","operationId":"settings_api_keys_settings_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/web/switch-org":{"post":{"summary":"Switch Org","description":"Switch the session's active organization (and thus the active drive).\n\nA user can belong to multiple orgs (e.g. a personal org + a shared/business\norg). v1 binds the active org at login with no way to change it; this lets a\nmember flip it. Membership is re-verified server-side (the form value is\nattacker-controllable), then the session cookie is re-minted with the new\nactive org — `current_drive`'s membership JOIN enforces access on the next\nrequest. Any `reveal_key` is dropped: it was scoped to the old drive.","operationId":"switch_org_web_switch_org_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_switch_org_web_switch_org_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/settings/quickstart":{"get":{"summary":"Settings Quickstart","description":"Quickstart tab — the single connect-and-use surface, consolidating the\nformer Skill + MCP-setup tabs. Hero is the copy-paste bootstrap prompt\n(for terminal-less agents); the `claude mcp add` one-liner is second (for\nClaude Code). Connected clients fold into a collapsible section below.\n\nThe full tool reference lives at `/agentdrive.md` (rendered from\n`skills/SKILL.md`); the bootstrap prompt points the agent there rather\nthan inlining it here, keeping the tab drift-free.","operationId":"settings_quickstart_settings_quickstart_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/settings/usage":{"get":{"summary":"Settings Usage","description":"Usage tab — current-period meters against tier caps.\n\nReads the same data as `GET /v0/drives/me/usage` but renders it as\nHTML directly so the page doesn't need a JS fetch round-trip. The\ntemplate computes the percentage and warning state per-row from\nthe `used` / `limit` pair; `limit == 0` is the unlimited sentinel\nand the template hides the cap line in that case.","operationId":"settings_usage_settings_usage_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/settings/danger":{"get":{"summary":"Danger Zone","operationId":"danger_zone_settings_danger_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard/danger":{"get":{"summary":"Danger Zone Old","operationId":"danger_zone_old_dashboard_danger_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/web/oauth/disconnect":{"post":{"summary":"Oauth Disconnect","description":"Disconnect one MCP client: revoke its whole rotation chain\n(mcp-oauth-design §4.8). Ownership is checked against the chain's\nuser_id — the form value is attacker-controllable.","operationId":"oauth_disconnect_web_oauth_disconnect_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_oauth_disconnect_web_oauth_disconnect_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/keys/rotate":{"post":{"summary":"Rotate Key","operationId":"rotate_key_web_keys_rotate_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_rotate_key_web_keys_rotate_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/keys/delete":{"post":{"summary":"Delete Key","operationId":"delete_key_web_keys_delete_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_delete_key_web_keys_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/account/delete":{"post":{"summary":"Delete Account","description":"Soft-delete the user + their solo workspace + drive.\n\nv1 semantics (solo orgs): deleting the account also deletes the\nworkspace and its data under one aligned retention window, after\nwhich everything is hard-purged. \"Delete my account\" means \"delete\neverything mine,\" matching Notion / Linear / Slack consumer-tier\nsemantics. Membership-transfer for shared orgs lands in v1.5+.\n\nThe response routes through the auth provider's logout so the\nupstream session is cleared before the user returns, preventing a\nsilent re-authentication that would re-provision the just-deleted\naccount. Falls back to a local-only redirect when there is no\nupstream session to clear.","operationId":"delete_account_web_account_delete_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_delete_account_web_account_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web/account/indexing":{"post":{"summary":"Toggle Indexing","description":"Flip the per-drive `indexing_enabled` flag (privacy opt-out for\nsending file content to Gemini). Checkbox semantics: a checked HTML\n`<input type=checkbox name=enabled value=on>` POSTs `enabled=on`;\nunchecked posts NO `enabled` field at all, which Form(default='')\nsurfaces as the empty string.","operationId":"toggle_indexing_web_account_indexing_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_toggle_indexing_web_account_indexing_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/feedback":{"get":{"summary":"Feedback Form","description":"Render the feedback form. Auth-required.","operationId":"feedback_form_feedback_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Feedback Submit","description":"Validate, charge the feedback budget, insert the ticket,\nredirect with a flash.\n\nValidation runs BEFORE the quota charge so users get clear field\nerrors without burning budget. The ticket insert is LLM-free and\nGitHub-free (§5.2) — the triage lane picks it up on its next tick.","operationId":"feedback_submit_feedback_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_feedback_submit_feedback_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/welcome":{"get":{"summary":"Welcome","description":"Show the three-step welcome screen and consume `reveal_key`.\n\nAuth-required. If no key is in the session, redirect onward to\n`/dashboard` (the user has already saved theirs, or is a\nreturning visitor who arrived here by typing the URL).","operationId":"welcome_welcome_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy":{"get":{"summary":"Privacy Page","description":"Public privacy & data-handling disclosure. Linked from the marketing\nfooter and the per-drive privacy settings card. Public — same disclosure\nfor every visitor; no per-drive personalization.","operationId":"privacy_page_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"summary":"Terms Page","description":"Public beta terms of service. Linked from the marketing footer.","operationId":"terms_page_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/":{"get":{"summary":"Marketing","operationId":"marketing__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/marketplace":{"get":{"summary":"Marketplace Browse","operationId":"marketplace_browse_marketplace_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/marketplace/{slug}":{"get":{"summary":"Marketplace Detail","operationId":"marketplace_detail_marketplace__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/publishers/{handle}":{"get":{"summary":"Publisher Profile","operationId":"publisher_profile_publishers__handle__get","parameters":[{"name":"handle","in":"path","required":true,"schema":{"type":"string","title":"Handle"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/collections/{slug}":{"get":{"summary":"Collection Detail","operationId":"collection_detail_collections__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/activity":{"get":{"summary":"Activity Feed","operationId":"activity_feed_activity_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/shared":{"get":{"summary":"Shared Files","operationId":"shared_files_shared_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/connectors":{"get":{"summary":"Connectors Page","description":"Connectors landing — Google Drive, Notion, etc. Each connector pipes\nits files into a virtual folder at the drive root (`gdrive/`, `notion/`)\nso the indexer can build wiki pages across all of an org's knowledge.\nNo backend in v0; cards read from `mock/data.py`.","operationId":"connectors_page_connectors_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/webhooks":{"get":{"summary":"Webhooks Page","operationId":"webhooks_page_webhooks_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/preview/artifact-detail":{"get":{"summary":"Artifact Detail Preview","operationId":"artifact_detail_preview_preview_artifact_detail_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/s/{share_key}":{"get":{"summary":"Redeem Share","operationId":"redeem_share_s__share_key__get","parameters":[{"name":"share_key","in":"path","required":true,"schema":{"type":"string","title":"Share Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Redeem Share With Password","operationId":"redeem_share_with_password_s__share_key__post","parameters":[{"name":"share_key","in":"path","required":true,"schema":{"type":"string","title":"Share Key"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_redeem_share_with_password_s__share_key__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/a/{art_id}":{"get":{"summary":"View Permalink Artifact","description":"Resolve a stable artifact ID to its path-URL and 302 there.\n\nAuth model matches the path URL: public artifacts redirect for\nanyone; private artifacts redirect only for the owner. Non-owners\non private artifacts get 404 — same response as \"doesn't exist\",\nso the ID's existence isn't leaked. The forwarded query-param\nallowlist is `raw`, `download` (see _PERMALINK_FORWARDED_PARAMS).","operationId":"view_permalink_artifact_a__art_id__get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/a/{art_id}/head":{"get":{"summary":"View Artifact Head","description":"Return `{\"version\": <head version_number>}` for a readable artifact.\n\nAuth mirrors the permalink/viewer: the owner, or an `anyone:viewer`\ngrant (a published artifact), reads. Two deliberate differences from\nthe HTML viewer:\n\n  * Never redirect to login. A poll is a background `fetch`, not a\n    navigation — an HTML login page would be a useless body and a\n    same-origin redirect the client can't act on. Anonymous callers\n    on a private/absent artifact get a flat 404.\n  * \"Doesn't exist\" and \"exists but not readable\" collapse to the\n    same 404, so an anonymous poller can't use this as an existence\n    oracle (matches the permalink/viewer leak guard).","operationId":"view_artifact_head_a__art_id__head_get","parameters":[{"name":"art_id","in":"path","required":true,"schema":{"type":"string","title":"Art Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/f/{fld_id}":{"get":{"summary":"View Permalink Folder","description":"Resolve a stable folder ID to its current path-URL and 302.\n\nAuth model mirrors the artifact permalink: public folder = anon\nOK; private folder = owner only, otherwise 404 (no existence\nleak). \"Public\" is an `anyone:viewer` grant on the `fld_*` id\nresolved through `can_read` (§4.4); folders carry no visibility\nflag of their own.","operationId":"view_permalink_folder_f__fld_id__get","parameters":[{"name":"fld_id","in":"path","required":true,"schema":{"type":"string","title":"Fld Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{drive_id}/{path}":{"get":{"summary":"View File","operationId":"view_file__drive_id___path__get","parameters":[{"name":"drive_id","in":"path","required":true,"schema":{"type":"string","title":"Drive Id"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}},{"name":"raw","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Raw"}},{"name":"download","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Download"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","description":"Liveness + DB-reachability probe. Used by Cloud Run / k8s healthchecks\nand any uptime monitor. Returns 200 only if the DB pool can serve a\ntrivial query; 503 otherwise so the orchestrator can pull the instance\nout of rotation.\n\nNOTE: route is `/health`, NOT `/healthz`. Google's edge infrastructure\nintercepts `/healthz` (legacy kubernetes-reserved path) and returns a\ngeneric 404 before traffic reaches Cloud Run — discovered the hard way\nduring the first prod deploy. Don't rename back.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AnonymousIdentityResponse":{"properties":{"identity_assertion":{"type":"string","title":"Identity Assertion","description":"JWT signed by AgentDrive, scope=pre_claim. 30-day TTL."},"claim_token":{"type":"string","title":"Claim Token","description":"Opaque server-issued secret. Present at POST /agent/identity/claim and at POST /oauth2/token (grant_type=claim)."},"claim_metadata":{"$ref":"#/components/schemas/ClaimMetadata"},"drive_id":{"type":"string","title":"Drive Id"},"agent_identity_id":{"type":"string","title":"Agent Identity Id"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["identity_assertion","claim_token","claim_metadata","drive_id","agent_identity_id","expires_at"],"title":"AnonymousIdentityResponse","description":"`POST /agent/identity` response on the anonymous path.\n\nThe agent stores `identity_assertion` as its long-lived credential\nand uses `claim_token` to initiate the claim ceremony when the\nhuman is ready."},"ArtifactOut":{"properties":{"id":{"type":"string","title":"Id"},"drive_id":{"type":"string","title":"Drive Id"},"path":{"type":"string","title":"Path"},"url":{"type":"string","title":"Url"},"content_type":{"type":"string","title":"Content Type"},"file_type":{"type":"string","title":"File Type"},"size_bytes":{"type":"integer","title":"Size Bytes"},"hash":{"type":"string","title":"Hash"},"version_number":{"type":"integer","title":"Version Number","default":1},"labels":{"items":{"type":"string"},"type":"array","title":"Labels"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"source":{"anyOf":[{"$ref":"#/components/schemas/ArtifactSource"},{"type":"null"}]},"indexed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Indexed At"},"embedded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Embedded At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"llm_index":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Llm Index"}},"type":"object","required":["id","drive_id","path","url","content_type","file_type","size_bytes","hash","created_at","updated_at"],"title":"ArtifactOut"},"ArtifactSource":{"properties":{"refs":{"items":{"$ref":"#/components/schemas/SourceRef"},"type":"array","title":"Refs"}},"type":"object","title":"ArtifactSource","description":"Caller-supplied provenance metadata, attached to an artifact.\n\nv0.6 model: a list of typed refs. The legacy v0.5 fields\n(`agent_id`, `run_id`, `prompt_hash`) were never validated and are\nsuperseded by the `refs` shape (an agent-id ref would be\n`{\"type\": \"agent\", \"id\": \"...\"}` in v0.6 vocabulary)."},"Body_authorize_decision_oauth2_authorize_post":{"properties":{"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_authorize_decision_oauth2_authorize_post"},"Body_claim_complete_agent_identity_claim_complete_post":{"properties":{"claim_attempt_token":{"type":"string","title":"Claim Attempt Token"},"user_code":{"type":"string","title":"User Code"},"decision":{"type":"string","title":"Decision","default":"approve"},"org_name":{"type":"string","title":"Org Name","default":""},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["claim_attempt_token","user_code","csrf"],"title":"Body_claim_complete_agent_identity_claim_complete_post"},"Body_delete_account_web_account_delete_post":{"properties":{"confirm":{"type":"string","title":"Confirm"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["confirm","csrf"],"title":"Body_delete_account_web_account_delete_post"},"Body_delete_key_web_keys_delete_post":{"properties":{"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_delete_key_web_keys_delete_post"},"Body_feedback_submit_feedback_post":{"properties":{"category":{"type":"string","title":"Category","default":""},"title":{"type":"string","title":"Title","default":""},"message":{"type":"string","title":"Message","default":""},"contact":{"type":"string","title":"Contact","default":""},"attachments":{"items":{"type":"string","contentMediaType":"application/octet-stream"},"type":"array","title":"Attachments","default":[]},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_feedback_submit_feedback_post"},"Body_logout_auth_logout_post":{"properties":{"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_logout_auth_logout_post"},"Body_oauth2_token_oauth2_token_post":{"properties":{"grant_type":{"type":"string","title":"Grant Type"},"assertion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assertion"},"claim_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claim Token"}},"type":"object","required":["grant_type"],"title":"Body_oauth2_token_oauth2_token_post"},"Body_oauth_disconnect_web_oauth_disconnect_post":{"properties":{"chain_id":{"type":"string","title":"Chain Id"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["chain_id","csrf"],"title":"Body_oauth_disconnect_web_oauth_disconnect_post"},"Body_recovery_new_account_auth_recovery_new_account_post":{"properties":{"claim":{"type":"string","title":"Claim","default":"bind"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_recovery_new_account_auth_recovery_new_account_post"},"Body_recovery_restore_auth_recovery_restore_post":{"properties":{"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_recovery_restore_auth_recovery_restore_post"},"Body_redeem_share_with_password_s__share_key__post":{"properties":{"password":{"type":"string","title":"Password","default":""}},"type":"object","title":"Body_redeem_share_with_password_s__share_key__post"},"Body_rotate_key_web_keys_rotate_post":{"properties":{"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_rotate_key_web_keys_rotate_post"},"Body_switch_org_web_switch_org_post":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["organization_id","csrf"],"title":"Body_switch_org_web_switch_org_post"},"Body_toggle_indexing_web_account_indexing_post":{"properties":{"enabled":{"type":"string","title":"Enabled","default":""},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_toggle_indexing_web_account_indexing_post"},"Body_web_copy_artifact_web_artifacts_copy_post":{"properties":{"art_id":{"type":"string","title":"Art Id"},"new_path":{"type":"string","title":"New Path"},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["art_id","new_path","csrf"],"title":"Body_web_copy_artifact_web_artifacts_copy_post"},"Body_web_delete_artifact_op_web_artifacts_delete_post":{"properties":{"path":{"type":"string","title":"Path"},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["path","csrf"],"title":"Body_web_delete_artifact_op_web_artifacts_delete_post"},"Body_web_delete_folder_web_folders_delete_post":{"properties":{"fld_id":{"type":"string","title":"Fld Id"},"recursive":{"type":"string","title":"Recursive","default":""},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["fld_id","csrf"],"title":"Body_web_delete_folder_web_folders_delete_post"},"Body_web_move_folder_web_folders_move_post":{"properties":{"fld_id":{"type":"string","title":"Fld Id"},"new_path":{"type":"string","title":"New Path"},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["fld_id","new_path","csrf"],"title":"Body_web_move_folder_web_folders_move_post"},"Body_web_new_folder_web_folders_new_post":{"properties":{"parent":{"type":"string","title":"Parent","default":""},"name":{"type":"string","title":"Name"},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["name","csrf"],"title":"Body_web_new_folder_web_folders_new_post"},"Body_web_project_compile_web_projects__fld_id__compile_post":{"properties":{"engine":{"type":"string","title":"Engine","default":""},"entrypoint":{"type":"string","title":"Entrypoint","default":""},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["csrf"],"title":"Body_web_project_compile_web_projects__fld_id__compile_post"},"Body_web_rename_artifact_web_artifacts_rename_post":{"properties":{"art_id":{"type":"string","title":"Art Id"},"new_path":{"type":"string","title":"New Path"},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["art_id","new_path","csrf"],"title":"Body_web_rename_artifact_web_artifacts_rename_post"},"Body_web_restore_artifact_web_artifacts_restore_post":{"properties":{"art_id":{"type":"string","title":"Art Id"},"return_to":{"type":"string","title":"Return To","default":"/web/trash"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["art_id","csrf"],"title":"Body_web_restore_artifact_web_artifacts_restore_post"},"Body_web_restore_folder_web_folders_restore_post":{"properties":{"fld_id":{"type":"string","title":"Fld Id"},"return_to":{"type":"string","title":"Return To","default":"/web/trash"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["fld_id","csrf"],"title":"Body_web_restore_folder_web_folders_restore_post"},"Body_web_set_metadata_web_set_post":{"properties":{"target":{"type":"string","title":"Target"},"description":{"type":"string","title":"Description","default":""},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["target","csrf"],"title":"Body_web_set_metadata_web_set_post"},"Body_web_upload_web_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"dest_dir":{"type":"string","title":"Dest Dir","default":""},"return_to":{"type":"string","title":"Return To","default":"/dashboard"},"csrf":{"type":"string","title":"Csrf"}},"type":"object","required":["file","csrf"],"title":"Body_web_upload_web_upload_post"},"ClaimInitRequest":{"properties":{"claim_token":{"type":"string","title":"Claim Token","description":"The per-identity claim_token returned by POST /agent/identity."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Optional hint to display on the /claim page so the human knows which account the agent expected. Not enforced (design §14 question #3)."}},"type":"object","required":["claim_token"],"title":"ClaimInitRequest","description":"`POST /agent/identity/claim` body."},"ClaimInitResponse":{"properties":{"claim_attempt_token":{"type":"string","title":"Claim Attempt Token","description":"Per-attempt opaque token; the agent does not need to present it."},"user_code":{"type":"string","title":"User Code","description":"Human-readable code the user types/sees on /claim."},"verification_uri":{"type":"string","title":"Verification Uri","description":"URL to direct the human to."},"verification_uri_complete":{"type":"string","title":"Verification Uri Complete","description":"Convenience: same as `verification_uri` but with the user_code pre-baked so the human doesn't have to type it. RFC 8628 idiom."},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["claim_attempt_token","user_code","verification_uri","verification_uri_complete","expires_at"],"title":"ClaimInitResponse"},"ClaimMetadata":{"properties":{"claim_endpoint":{"type":"string","title":"Claim Endpoint"},"supported_email_hints":{"type":"boolean","title":"Supported Email Hints","default":true}},"type":"object","required":["claim_endpoint"],"title":"ClaimMetadata","description":"Hints the agent's UI/CLI can use when initiating the claim\nceremony. Decoupled from the `claim_token` itself so future\nadditions don't change the token's shape."},"CompileJobIn":{"properties":{"task":{"type":"string","title":"Task","default":"latex.compile"},"options":{"$ref":"#/components/schemas/CompileOptions","default":{"wait":false}}},"type":"object","title":"CompileJobIn"},"CompileOptions":{"properties":{"entrypoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entrypoint"},"engine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Engine"},"wait":{"type":"boolean","title":"Wait","default":false}},"type":"object","title":"CompileOptions"},"CopyIn":{"properties":{"path":{"type":"string","title":"Path"},"source":{"anyOf":[{"$ref":"#/components/schemas/ArtifactSource"},{"type":"null"}]}},"type":"object","required":["path"],"title":"CopyIn","description":"POST /v0/artifacts/{art_id}/copy body — duplicate to new path."},"DownloadUrlOut":{"properties":{"download_url":{"type":"string","title":"Download Url"},"direct":{"type":"boolean","title":"Direct"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"size_bytes":{"type":"integer","title":"Size Bytes"},"content_type":{"type":"string","title":"Content Type"},"filename":{"type":"string","title":"Filename"}},"type":"object","required":["download_url","direct","size_bytes","content_type","filename"],"title":"DownloadUrlOut","description":"A URL the caller can GET to fetch the artifact's bytes.\n\n`direct=True` ⇒ a short-lived signed GCS URL on `storage.googleapis.com`\n(client downloads straight from GCS; `expires_at` is set). `direct=False`\n⇒ the proxy `/download` endpoint on the API host (no expiry) — returned for\nsub-threshold artifacts or when signing is unavailable. The URL is opaque:\ncallers should not parse it. See large-download-design.md §5.1."},"EventOut":{"properties":{"id":{"type":"string","title":"Id"},"drive_id":{"type":"string","title":"Drive Id"},"art_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Art Id"},"actor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Name"},"action":{"type":"string","title":"Action"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","drive_id","action","created_at"],"title":"EventOut"},"EventPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/EventOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"EventPage"},"ExtensionExchangeRequest":{"properties":{"ext_id":{"type":"string","title":"Ext Id","description":"The extension's ID (Chrome Web Store ID or unpacked dev ID)."},"ticket":{"type":"string","title":"Ticket","description":"The opaque ticket from the /auth/callback handoff."}},"type":"object","required":["ext_id","ticket"],"title":"ExtensionExchangeRequest","description":"Single-use ticket → JWT pair. Called by `auth-complete.html`\ninside the SnipIt extension. No `Authorization` header — the\nticket itself is the credential."},"ExtensionExchangeResponse":{"properties":{"access_token":{"type":"string","title":"Access Token","description":"15-minute access_token (scope=extension)."},"token_type":{"type":"string","title":"Token Type","default":"Bearer"},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds until access_token expiry."},"scope":{"type":"string","const":"extension","title":"Scope","default":"extension"},"identity_assertion":{"type":"string","title":"Identity Assertion","description":"90-day identity_assertion. Refresh via POST /oauth2/token."},"drive_id":{"type":"string","title":"Drive Id","description":"The drive these credentials are scoped to."}},"type":"object","required":["access_token","expires_in","identity_assertion","drive_id"],"title":"ExtensionExchangeResponse"},"FindHitOut":{"properties":{"art_id":{"type":"string","title":"Art Id"},"drive_id":{"type":"string","title":"Drive Id"},"path":{"type":"string","title":"Path"},"url":{"type":"string","title":"Url"},"content_type":{"type":"string","title":"Content Type"},"file_type":{"type":"string","title":"File Type"},"labels":{"items":{"type":"string"},"type":"array","title":"Labels"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"version_number":{"type":"integer","title":"Version Number"},"modality":{"type":"string","enum":["text","code","pdf","image","audio","video"],"title":"Modality"},"ord":{"type":"integer","title":"Ord"},"text":{"type":"string","title":"Text"},"snippet":{"type":"string","title":"Snippet"},"score":{"type":"number","title":"Score"},"rank_lexical":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank Lexical"},"rank_semantic":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank Semantic"},"char_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Char Start"},"char_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Char End"},"page_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Start"},"page_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page End"},"time_start_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Start Ms"},"time_end_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time End Ms"}},"type":"object","required":["art_id","drive_id","path","url","content_type","file_type","updated_at","version_number","modality","ord","text","snippet","score"],"title":"FindHitOut","description":"One passage-level hit from `/v0/find` (hybrid chunk RAG over\n`embed_chunks`). The unit is a passage, not a file — consecutive\n`ord` values from the same `art_id` are normal because chunks\noverlap by ~400 tokens. Span fields are modality-aware: only the\npair matching `modality` is populated, the others stay None."},"FindPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FindHitOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"FindPage"},"FolderCreateIn":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"FolderCreateIn","description":"POST /v0/folders/{path}? body for the optional metadata params.\nEmpty body is fine — `mkdir` with no description just creates the\nfolder row."},"FolderDeleteOut":{"properties":{"ok":{"type":"boolean","title":"Ok","default":true},"id":{"type":"string","title":"Id"},"path":{"type":"string","title":"Path"},"deleted_at":{"type":"string","format":"date-time","title":"Deleted At"},"purge_at":{"type":"string","format":"date-time","title":"Purge At"},"retention_days":{"type":"integer","title":"Retention Days"},"n_subfolders_deleted":{"type":"integer","title":"N Subfolders Deleted"},"n_artifacts_deleted":{"type":"integer","title":"N Artifacts Deleted"}},"type":"object","required":["id","path","deleted_at","purge_at","retention_days","n_subfolders_deleted","n_artifacts_deleted"],"title":"FolderDeleteOut","description":"DELETE response — surfaces cascade counts so the caller can\nconfirm scope of an rmdir before the client retries with\n`?recursive=true`."},"FolderMoveIn":{"properties":{"path":{"type":"string","title":"Path"}},"type":"object","required":["path"],"title":"FolderMoveIn","description":"POST /v0/folders/{fld_id}/move body — rename / move."},"FolderOut":{"properties":{"id":{"type":"string","title":"Id"},"drive_id":{"type":"string","title":"Drive Id"},"path":{"type":"string","title":"Path"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"inherit_grants":{"type":"boolean","title":"Inherit Grants","default":true},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"},"purge_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Purge At"}},"type":"object","required":["id","drive_id","path","created_at","updated_at"],"title":"FolderOut","description":"Folder resource (folders+permalinks design §13). `path` is the\ncanonical leading+trailing-slash form. Access is expressed through\ngrants (permission-sharing-design §4.4), not a folder-level flag."},"FolderPatchIn":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"inherit_grants":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Inherit Grants"}},"type":"object","title":"FolderPatchIn","description":"PATCH /v0/folders/{fld_id} body — partial update. Field absence =\nunchanged. `description`: explicit null = clear. `inherit_grants`:\nnon-nullable — null/absent = unchanged (it cannot be cleared, only\nflipped true/false)."},"GrantCreateIn":{"properties":{"resource":{"type":"string","title":"Resource"},"principal":{"$ref":"#/components/schemas/GrantPrincipalIn"},"role":{"type":"string","enum":["viewer","commenter","editor","manager"],"title":"Role"},"expires_in":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires In"}},"type":"object","required":["resource","principal","role"],"title":"GrantCreateIn","description":"POST /v0/grants body. `resource` is an `art_*`/`fld_*` id or a path\n(resolved within the caller's drive). `expires_in` is seconds from now\n(omit for a permanent grant)."},"GrantIn":{"properties":{"principal":{"type":"string","title":"Principal"},"role":{"type":"string","title":"Role","default":"viewer"}},"type":"object","required":["principal"],"title":"GrantIn"},"GrantList":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GrantOut"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"GrantList"},"GrantOut":{"properties":{"id":{"type":"string","title":"Id"},"resource_type":{"type":"string","enum":["artifact","folder"],"title":"Resource Type"},"resource_id":{"type":"string","title":"Resource Id"},"principal_type":{"type":"string","enum":["user","agent","org","anyone"],"title":"Principal Type"},"principal_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal Id"},"principal_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal Email"},"role":{"type":"string","title":"Role"},"granted_by_type":{"type":"string","title":"Granted By Type"},"granted_by_id":{"type":"string","title":"Granted By Id"},"on_behalf_of":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"On Behalf Of"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"artifacts_affected":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Artifacts Affected"}},"type":"object","required":["id","resource_type","resource_id","principal_type","role","granted_by_type","granted_by_id","created_at"],"title":"GrantOut","description":"A live grant. Audit fields (`granted_by_*`, `on_behalf_of`) are\nsurfaced so a manager can see who shared what."},"GrantPatchIn":{"properties":{"role":{"anyOf":[{"type":"string","enum":["viewer","commenter","editor","manager"]},{"type":"null"}],"title":"Role"},"expires_in":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires In"}},"type":"object","title":"GrantPatchIn","description":"PATCH /v0/grants/{grn_id} body. Field absence = unchanged; explicit\n`expires_in: null` clears the expiry (makes the grant permanent)."},"GrantPrincipalIn":{"properties":{"type":{"type":"string","enum":["user","agent","org","anyone"],"title":"Type"},"id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Id"},"email":{"anyOf":[{"type":"string","maxLength":320},{"type":"null"}],"title":"Email"}},"type":"object","required":["type"],"title":"GrantPrincipalIn","description":"Who a grant is for. `anyone` carries no id/email; `org`/`agent`\nrequire `id`; `user` requires exactly one of `id` / `email` (an email\nwith no account becomes a pending-email invite resolved on sign-in)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LinkIn":{"properties":{"password":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Password"},"expires_in":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires In"}},"type":"object","title":"LinkIn"},"Page":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ArtifactOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page"},"ProjectConfigIn":{"properties":{"entrypoint":{"type":"string","title":"Entrypoint"},"engine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Engine"},"auto_compile":{"type":"boolean","title":"Auto Compile","default":false}},"type":"object","required":["entrypoint"],"title":"ProjectConfigIn"},"PublicIn":{"properties":{"public":{"type":"boolean","title":"Public"}},"type":"object","required":["public"],"title":"PublicIn"},"RenameIn":{"properties":{"path":{"type":"string","title":"Path"}},"type":"object","required":["path"],"title":"RenameIn","description":"PATCH /v0/artifacts/{art_id} body — rename / move."},"SealIn":{"properties":{"inherit_grants":{"type":"boolean","title":"Inherit Grants"}},"type":"object","required":["inherit_grants"],"title":"SealIn"},"SearchHitOut":{"properties":{"drive_id":{"type":"string","title":"Drive Id"},"path":{"type":"string","title":"Path"},"url":{"type":"string","title":"Url"},"content_type":{"type":"string","title":"Content Type"},"file_type":{"type":"string","title":"File Type"},"labels":{"items":{"type":"string"},"type":"array","title":"Labels"},"snippet":{"type":"string","title":"Snippet"},"score":{"type":"number","title":"Score"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["drive_id","path","url","content_type","file_type","snippet","score","updated_at"],"title":"SearchHitOut"},"SearchPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SearchHitOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"SearchPage"},"ShareCreateIn":{"properties":{"resource":{"type":"string","title":"Resource"},"role":{"type":"string","enum":["viewer","commenter","editor"],"title":"Role","default":"viewer"},"expires_in":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires In"},"password":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Password"}},"type":"object","required":["resource"],"title":"ShareCreateIn","description":"POST /v0/shares body. `resource` is an `art_*`/`fld_*` id or a path.\n`expires_in` is seconds from now (omit for the default: none for a human\ncreator, a short TTL for an agent). `password` (optional) gates redemption."},"ShareList":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShareOut"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"ShareList"},"ShareMintOut":{"properties":{"id":{"type":"string","title":"Id"},"resource_type":{"type":"string","enum":["artifact","folder"],"title":"Resource Type"},"resource_id":{"type":"string","title":"Resource Id"},"role":{"type":"string","title":"Role"},"audience":{"type":"string","title":"Audience"},"has_password":{"type":"boolean","title":"Has Password"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"last_accessed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Accessed At"},"access_count":{"type":"integer","title":"Access Count","default":0},"share_key":{"type":"string","title":"Share Key"},"url":{"type":"string","title":"Url"}},"type":"object","required":["id","resource_type","resource_id","role","audience","has_password","created_at","share_key","url"],"title":"ShareMintOut","description":"The create/rotate response — the ONLY place the `share_key` and its\nredemption `url` are exposed."},"ShareOut":{"properties":{"id":{"type":"string","title":"Id"},"resource_type":{"type":"string","enum":["artifact","folder"],"title":"Resource Type"},"resource_id":{"type":"string","title":"Resource Id"},"role":{"type":"string","title":"Role"},"audience":{"type":"string","title":"Audience"},"has_password":{"type":"boolean","title":"Has Password"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"last_accessed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Accessed At"},"access_count":{"type":"integer","title":"Access Count","default":0}},"type":"object","required":["id","resource_type","resource_id","role","audience","has_password","created_at"],"title":"ShareOut","description":"A live share link as seen on list/management — NEVER carries the\n`share_key` (that is the credential, returned only at mint/rotate)."},"SourceRef":{"properties":{"type":{"type":"string","title":"Type"},"id":{"type":"string","title":"Id"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["type","id"],"title":"SourceRef","description":"One typed provenance ref. `type` is open-vocabulary (server\nvalidates only length, not the value), so callers can declare new\ntypes as their integrations evolve. `id` is the type-specific\nidentifier — for `type='artifact'` this is an `art_…` ID."},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"Bearer"},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds until access_token expiry."},"scope":{"type":"string","title":"Scope"},"identity_assertion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Identity Assertion"}},"type":"object","required":["access_token","expires_in","scope"],"title":"TokenResponse","description":"`POST /oauth2/token` success response. Mirrors RFC 6749 with\nan optional `identity_assertion` field for the claim grant path\n(where a fresh post-claim assertion supersedes the pre-claim\none)."},"UploadBeginIn":{"properties":{"path":{"type":"string","title":"Path"},"content_type":{"type":"string","title":"Content Type","default":"application/octet-stream"},"size_bytes":{"type":"integer","minimum":1.0,"title":"Size Bytes"},"crc32c":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crc32C"},"labels":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Labels"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"source":{"anyOf":[{"$ref":"#/components/schemas/ArtifactSource"},{"type":"null"}]},"actor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Name"},"change_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Change Summary"},"if_match":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"If Match"}},"type":"object","required":["path","size_bytes"],"title":"UploadBeginIn","description":"Body of `POST /v0/uploads` — the large-upload begin call (large-upload-\ndesign.md §5.1). All artifact decisions are frozen here; the subsequent\nGCS PUT carries only bytes, and `commit` carries only the `upload_id`.\n\n`labels`/`metadata`/`source` omitted (null) ⇒ preserve the existing\nartifact's value at commit; present (incl. empty) ⇒ replace."},"UploadBeginOut":{"properties":{"upload_id":{"type":"string","title":"Upload Id"},"upload_url":{"type":"string","title":"Upload Url"},"method":{"type":"string","const":"PUT","title":"Method","default":"PUT"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"max_bytes":{"type":"integer","title":"Max Bytes"}},"type":"object","required":["upload_id","upload_url","headers","expires_at","max_bytes"],"title":"UploadBeginOut","description":"Response of `POST /v0/uploads`. PUT the bytes to `upload_url` (no auth\nheader — the URL is the credential), then `POST .../commit`."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VersionOut":{"properties":{"art_id":{"type":"string","title":"Art Id"},"version_number":{"type":"integer","title":"Version Number"},"size_bytes":{"type":"integer","title":"Size Bytes"},"hash":{"type":"string","title":"Hash"},"content_type":{"type":"string","title":"Content Type"},"actor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Name"},"change_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Change Summary"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["art_id","version_number","size_bytes","hash","content_type","created_at"],"title":"VersionOut"},"VersionPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/VersionOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"pruned_before":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pruned Before"}},"type":"object","required":["items"],"title":"VersionPage"}}}}