The lq-ai contract & upstream loop
Donna implements no legal-AI logic — it consumes a contract. This is what happens when the contract isn't enough: file an ask, relay it, bump the pin.
src/lib/api/backend.d.ts12035 lines
Outline 5 symbols
- paths interface export
- webhooks type export
- components interface export
- $defs type export
- operations type export
1/**
2 * This file was auto-generated by openapi-typescript.
3 * Do not make direct changes to the file.
4 */
5
6export interface paths {
7 "/api/v1/auth/login": {
8 parameters: {
9 query?: never;
10 header?: never;
11 path?: never;
12 cookie?: never;
13 };
14 get?: never;
15 put?: never;
16 /** Authenticate with email and password */
17 post: {
18 parameters: {
19 query?: never;
20 header?: never;
21 path?: never;
22 cookie?: never;
23 };
24 requestBody: {
25 content: {
26 "application/json": components["schemas"]["LoginRequest"];
27 };
28 };
29 responses: {
30 /** @description Authentication successful */
31 200: {
32 headers: {
33 [name: string]: unknown;
34 };
35 content: {
36 "application/json": components["schemas"]["LoginResponse"];
37 };
38 };
39 /** @description Invalid credentials */
40 401: {
41 headers: {
42 [name: string]: unknown;
43 };
44 content?: never;
45 };
46 /** @description MFA required */
47 423: {
48 headers: {
49 [name: string]: unknown;
50 };
51 content: {
52 "application/json": components["schemas"]["MfaChallenge"];
53 };
54 };
55 };
56 };
57 delete?: never;
58 options?: never;
59 head?: never;
60 patch?: never;
61 trace?: never;
62 };
63 "/api/v1/auth/mfa/verify": {
64 parameters: {
65 query?: never;
66 header?: never;
67 path?: never;
68 cookie?: never;
69 };
70 get?: never;
71 put?: never;
72 /** Complete MFA challenge with TOTP code */
73 post: {
74 parameters: {
75 query?: never;
76 header?: never;
77 path?: never;
78 cookie?: never;
79 };
80 requestBody: {
81 content: {
82 "application/json": {
83 /** @description Token from the MFA challenge response */
84 mfa_token: string;
85 code: string;
86 };
87 };
88 };
89 responses: {
90 /** @description MFA verification successful */
91 200: {
92 headers: {
93 [name: string]: unknown;
94 };
95 content: {
96 "application/json": components["schemas"]["LoginResponse"];
97 };
98 };
99 /** @description Invalid MFA code */
100 401: {
101 headers: {
102 [name: string]: unknown;
103 };
104 content?: never;
105 };
106 };
107 };
108 delete?: never;
109 options?: never;
110 head?: never;
111 patch?: never;
112 trace?: never;
113 };
114 "/api/v1/auth/refresh": {
115 parameters: {
116 query?: never;
117 header?: never;
118 path?: never;
119 cookie?: never;
120 };
121 get?: never;
122 put?: never;
123 /** Refresh access token using refresh token */
124 post: {
125 parameters: {
126 query?: never;
127 header?: never;
128 path?: never;
129 cookie?: never;
130 };
131 requestBody: {
132 content: {
133 "application/json": {
134 refresh_token: string;
135 };
136 };
137 };
138 responses: {
139 /** @description New access token issued */
140 200: {
141 headers: {
142 [name: string]: unknown;
143 };
144 content: {
145 "application/json": components["schemas"]["TokenResponse"];
146 };
147 };
148 };
149 };
150 delete?: never;
151 options?: never;
152 head?: never;
153 patch?: never;
154 trace?: never;
155 };
156 "/api/v1/auth/logout": {
157 parameters: {
158 query?: never;
159 header?: never;
160 path?: never;
161 cookie?: never;
162 };
163 get?: never;
164 put?: never;
165 /** Invalidate the current refresh token */
166 post: {
167 parameters: {
168 query?: never;
169 header?: never;
170 path?: never;
171 cookie?: never;
172 };
173 requestBody?: never;
174 responses: {
175 /** @description Logout successful */
176 204: {
177 headers: {
178 [name: string]: unknown;
179 };
180 content?: never;
181 };
182 };
183 };
184 delete?: never;
185 options?: never;
186 head?: never;
187 patch?: never;
188 trace?: never;
189 };
190 "/api/v1/auth/mfa/setup": {
191 parameters: {
192 query?: never;
193 header?: never;
194 path?: never;
195 cookie?: never;
196 };
197 get?: never;
198 put?: never;
199 /**
200 * Enroll in TOTP-based MFA
201 * @description Bearer-authenticated. Issues a fresh TOTP secret, provisioning
202 * URI, and 10 single-use recovery codes. Persists the secret +
203 * bcrypt-hashed codes on the user, but does NOT enable MFA — the
204 * user must subsequently prove possession by submitting a TOTP
205 * code to `/auth/mfa/enable`. Re-running setup before enable
206 * overwrites the pending secret + codes; re-running after MFA is
207 * already enabled is a 409 (`mfa_already_enabled`).
208 */
209 post: {
210 parameters: {
211 query?: never;
212 header?: never;
213 path?: never;
214 cookie?: never;
215 };
216 requestBody?: never;
217 responses: {
218 /** @description TOTP enrollment data (provisioning URI + recovery codes) */
219 200: {
220 headers: {
221 [name: string]: unknown;
222 };
223 content: {
224 "application/json": {
225 secret: string;
226 /** @description otpauth:// URI for QR code */
227 provisioning_uri: string;
228 recovery_codes: string[];
229 };
230 };
231 };
232 /** @description MFA is already enabled (call `/auth/mfa/disable` first) */
233 409: {
234 headers: {
235 [name: string]: unknown;
236 };
237 content?: never;
238 };
239 };
240 };
241 delete?: never;
242 options?: never;
243 head?: never;
244 patch?: never;
245 trace?: never;
246 };
247 "/api/v1/auth/mfa/enable": {
248 parameters: {
249 query?: never;
250 header?: never;
251 path?: never;
252 cookie?: never;
253 };
254 get?: never;
255 put?: never;
256 /**
257 * Confirm TOTP enrollment with a verification code
258 * @description Bearer-authenticated. Verifies a 6-digit TOTP code against the
259 * pending secret stored by `/auth/mfa/setup`. On success flips
260 * `users.mfa_enabled` to TRUE; subsequent logins for this user
261 * return 423 + `MfaChallenge`.
262 */
263 post: {
264 parameters: {
265 query?: never;
266 header?: never;
267 path?: never;
268 cookie?: never;
269 };
270 requestBody: {
271 content: {
272 "application/json": {
273 code: string;
274 };
275 };
276 };
277 responses: {
278 /** @description MFA enabled */
279 204: {
280 headers: {
281 [name: string]: unknown;
282 };
283 content?: never;
284 };
285 /** @description Setup not started or code invalid */
286 400: {
287 headers: {
288 [name: string]: unknown;
289 };
290 content?: never;
291 };
292 /** @description MFA is already enabled */
293 409: {
294 headers: {
295 [name: string]: unknown;
296 };
297 content?: never;
298 };
299 };
300 };
301 delete?: never;
302 options?: never;
303 head?: never;
304 patch?: never;
305 trace?: never;
306 };
307 "/api/v1/auth/mfa/disable": {
308 parameters: {
309 query?: never;
310 header?: never;
311 path?: never;
312 cookie?: never;
313 };
314 get?: never;
315 put?: never;
316 /**
317 * Disable MFA after re-proving password and a current MFA code
318 * @description Bearer-authenticated. Requires both the user's current password
319 * AND a current TOTP code (or a single-use recovery code). On
320 * success clears the TOTP secret, recovery codes, and the
321 * `mfa_enabled` flag. Wrong-password and wrong-code branches both
322 * return 401 — the response shape does not reveal which leg
323 * failed.
324 */
325 post: {
326 parameters: {
327 query?: never;
328 header?: never;
329 path?: never;
330 cookie?: never;
331 };
332 requestBody: {
333 content: {
334 "application/json": {
335 password: string;
336 code: string;
337 };
338 };
339 };
340 responses: {
341 /** @description MFA disabled */
342 204: {
343 headers: {
344 [name: string]: unknown;
345 };
346 content?: never;
347 };
348 /** @description MFA is not enabled */
349 400: {
350 headers: {
351 [name: string]: unknown;
352 };
353 content?: never;
354 };
355 /** @description Invalid credentials or MFA code */
356 401: {
357 headers: {
358 [name: string]: unknown;
359 };
360 content?: never;
361 };
362 };
363 };
364 delete?: never;
365 options?: never;
366 head?: never;
367 patch?: never;
368 trace?: never;
369 };
370 "/api/v1/auth/change-password": {
371 parameters: {
372 query?: never;
373 header?: never;
374 path?: never;
375 cookie?: never;
376 };
377 get?: never;
378 put?: never;
379 /**
380 * Change the calling user's password
381 * @description Bearer-authenticated. Verifies the current password before
382 * accepting a new one (defense against a stolen access token).
383 * Clears `must_change_password` if it was set (used by the
384 * first-run admin flow per Task B2). Revokes all active sessions
385 * for the user; the caller must re-authenticate.
386 */
387 post: {
388 parameters: {
389 query?: never;
390 header?: never;
391 path?: never;
392 cookie?: never;
393 };
394 requestBody: {
395 content: {
396 "application/json": components["schemas"]["ChangePasswordRequest"];
397 };
398 };
399 responses: {
400 /** @description Password changed successfully */
401 204: {
402 headers: {
403 [name: string]: unknown;
404 };
405 content?: never;
406 };
407 /** @description New password fails policy (too short */
408 400: {
409 headers: {
410 [name: string]: unknown;
411 };
412 content?: never;
413 };
414 /** @description Bearer token invalid or current_password is wrong */
415 401: {
416 headers: {
417 [name: string]: unknown;
418 };
419 content?: never;
420 };
421 /**
422 * @description Reserved by the must-change-password gate elsewhere; the
423 * change-password endpoint itself is reachable while the gate
424 * is active.
425 */
426 403: {
427 headers: {
428 [name: string]: unknown;
429 };
430 content?: never;
431 };
432 };
433 };
434 delete?: never;
435 options?: never;
436 head?: never;
437 patch?: never;
438 trace?: never;
439 };
440 "/api/v1/users/me": {
441 parameters: {
442 query?: never;
443 header?: never;
444 path?: never;
445 cookie?: never;
446 };
447 /** Get current user */
448 get: {
449 parameters: {
450 query?: never;
451 header?: never;
452 path?: never;
453 cookie?: never;
454 };
455 requestBody?: never;
456 responses: {
457 /** @description Current user */
458 200: {
459 headers: {
460 [name: string]: unknown;
461 };
462 content: {
463 "application/json": components["schemas"]["User"];
464 };
465 };
466 };
467 };
468 put?: never;
469 post?: never;
470 delete?: never;
471 options?: never;
472 head?: never;
473 /**
474 * Update the caller's own profile (display_name)
475 * @description Bearer-authenticated. Caller-scoped — updates only the
476 * authenticated user's own row; no user id is accepted from the
477 * path or body. Currently edits `display_name` only: the value is
478 * trimmed, must be non-empty after trimming, and is length-capped
479 * (200 chars). Omitting `display_name` (or sending an empty body)
480 * is a 422 — there is nothing to update. Writes a
481 * `user.profile_updated` audit row listing the changed fields and
482 * returns the updated `User` (same shape as `GET /users/me`).
483 *
484 * Email self-service editing is intentionally out of scope on this
485 * surface — changing the login email pulls in re-verification, MFA,
486 * and uniqueness concerns and warrants its own dedicated flow (a
487 * future enhancement).
488 */
489 patch: {
490 parameters: {
491 query?: never;
492 header?: never;
493 path?: never;
494 cookie?: never;
495 };
496 requestBody: {
497 content: {
498 "application/json": components["schemas"]["UserProfileUpdate"];
499 };
500 };
501 responses: {
502 /** @description Updated user */
503 200: {
504 headers: {
505 [name: string]: unknown;
506 };
507 content: {
508 "application/json": components["schemas"]["User"];
509 };
510 };
511 /** @description Validation error (empty/whitespace/over-length display_name */
512 422: {
513 headers: {
514 [name: string]: unknown;
515 };
516 content?: never;
517 };
518 };
519 };
520 trace?: never;
521 };
522 "/api/v1/users/me/export": {
523 parameters: {
524 query?: never;
525 header?: never;
526 path?: never;
527 cookie?: never;
528 };
529 get?: never;
530 put?: never;
531 /**
532 * Request a per-user data export (GDPR Article 20)
533 * @description Bearer-authenticated. Inserts a `user_export_jobs` row with
534 * status `queued` and enqueues the worker job that builds +
535 * uploads the ZIP. Returns 202 immediately — clients poll the
536 * per-job endpoint below for completion.
537 */
538 post: {
539 parameters: {
540 query?: never;
541 header?: never;
542 path?: never;
543 cookie?: never;
544 };
545 requestBody?: never;
546 responses: {
547 /** @description Export job queued */
548 202: {
549 headers: {
550 [name: string]: unknown;
551 };
552 content: {
553 "application/json": {
554 /** Format: uuid */
555 job_id: string;
556 /** @enum {string} */
557 status: "queued" | "processing" | "completed" | "failed";
558 download_url?: string | null;
559 };
560 };
561 };
562 };
563 };
564 delete?: never;
565 options?: never;
566 head?: never;
567 patch?: never;
568 trace?: never;
569 };
570 "/api/v1/users/me/export/{job_id}": {
571 parameters: {
572 query?: never;
573 header?: never;
574 path?: never;
575 cookie?: never;
576 };
577 /**
578 * Poll a user-export job's status
579 * @description Bearer-authenticated. Returns the current status of the export
580 * job. When `status=completed` and the bundle has not yet expired,
581 * `download_url` is a presigned MinIO URL valid for 24 hours. A
582 * 404 covers both "no such job" and "job belongs to another user"
583 * (does not leak existence cross-user).
584 */
585 get: {
586 parameters: {
587 query?: never;
588 header?: never;
589 path: {
590 job_id: string;
591 };
592 cookie?: never;
593 };
594 requestBody?: never;
595 responses: {
596 /** @description Job status */
597 200: {
598 headers: {
599 [name: string]: unknown;
600 };
601 content: {
602 "application/json": {
603 /** Format: uuid */
604 job_id: string;
605 /** @enum {string} */
606 status: "queued" | "processing" | "completed" | "failed";
607 download_url?: string | null;
608 };
609 };
610 };
611 /** @description Job not found */
612 404: {
613 headers: {
614 [name: string]: unknown;
615 };
616 content?: never;
617 };
618 };
619 };
620 put?: never;
621 post?: never;
622 delete?: never;
623 options?: never;
624 head?: never;
625 patch?: never;
626 trace?: never;
627 };
628 "/api/v1/users/me/delete": {
629 parameters: {
630 query?: never;
631 header?: never;
632 path?: never;
633 cookie?: never;
634 };
635 get?: never;
636 put?: never;
637 /**
638 * Request account deletion (GDPR Article 17)
639 * @description Bearer-authenticated. Soft-schedules deletion: sets
640 * `users.deletion_scheduled_at = now() + gdpr_grace_period_days`,
641 * revokes all active sessions, and audit-logs the request. Login
642 * during the grace period is preserved so the user can call the
643 * cancel endpoint. Hard delete itself runs daily via a worker
644 * cron. Idempotent: re-calling returns the existing schedule
645 * rather than pushing it back.
646 */
647 post: {
648 parameters: {
649 query?: never;
650 header?: never;
651 path?: never;
652 cookie?: never;
653 };
654 requestBody?: never;
655 responses: {
656 /** @description Deletion queued */
657 202: {
658 headers: {
659 [name: string]: unknown;
660 };
661 content: {
662 "application/json": {
663 /** Format: date-time */
664 scheduled_deletion_at: string;
665 grace_period_days: number;
666 };
667 };
668 };
669 };
670 };
671 delete?: never;
672 options?: never;
673 head?: never;
674 patch?: never;
675 trace?: never;
676 };
677 "/api/v1/users/me/delete/cancel": {
678 parameters: {
679 query?: never;
680 header?: never;
681 path?: never;
682 cookie?: never;
683 };
684 get?: never;
685 put?: never;
686 /**
687 * Cancel a pending account deletion
688 * @description Bearer-authenticated. Clears `deletion_scheduled_at` if a
689 * pending deletion exists; returns 400 if there is no pending
690 * deletion to cancel. Only valid during the grace-period window —
691 * once the hard-delete worker has run, there is no user row to
692 * recover.
693 */
694 post: {
695 parameters: {
696 query?: never;
697 header?: never;
698 path?: never;
699 cookie?: never;
700 };
701 requestBody?: never;
702 responses: {
703 /** @description Pending deletion cancelled */
704 204: {
705 headers: {
706 [name: string]: unknown;
707 };
708 content?: never;
709 };
710 /** @description No pending deletion to cancel */
711 400: {
712 headers: {
713 [name: string]: unknown;
714 };
715 content?: never;
716 };
717 };
718 };
719 delete?: never;
720 options?: never;
721 head?: never;
722 patch?: never;
723 trace?: never;
724 };
725 "/api/v1/users/me/preferences": {
726 parameters: {
727 query?: never;
728 header?: never;
729 path?: never;
730 cookie?: never;
731 };
732 /**
733 * Read the caller's preferences (Wave A — PRD §3.2)
734 * @description Returns the preferences slice of the user profile. The same
735 * fields appear on ``GET /users/me``; this dedicated endpoint
736 * exists so frontends can subscribe to preferences changes
737 * without re-fetching the whole user object.
738 */
739 get: {
740 parameters: {
741 query?: never;
742 header?: never;
743 path?: never;
744 cookie?: never;
745 };
746 requestBody?: never;
747 responses: {
748 /** @description Preferences snapshot */
749 200: {
750 headers: {
751 [name: string]: unknown;
752 };
753 content: {
754 "application/json": components["schemas"]["UserPreferences"];
755 };
756 };
757 };
758 };
759 put?: never;
760 post?: never;
761 delete?: never;
762 options?: never;
763 head?: never;
764 /**
765 * Update the caller's preferences (partial)
766 * @description Only the fields the user supplies move. An idempotent PATCH
767 * (same value re-supplied) returns 200 without writing an audit
768 * row, matching the user_skills / saved_prompts pattern. Real
769 * changes write a ``user.preferences_updated`` audit row with
770 * before/after values in details.
771 */
772 patch: {
773 parameters: {
774 query?: never;
775 header?: never;
776 path?: never;
777 cookie?: never;
778 };
779 requestBody: {
780 content: {
781 "application/json": components["schemas"]["UserPreferencesUpdate"];
782 };
783 };
784 responses: {
785 /** @description Updated preferences */
786 200: {
787 headers: {
788 [name: string]: unknown;
789 };
790 content: {
791 "application/json": components["schemas"]["UserPreferences"];
792 };
793 };
794 };
795 };
796 trace?: never;
797 };
798 "/api/v1/enhance-prompt": {
799 parameters: {
800 query?: never;
801 header?: never;
802 path?: never;
803 cookie?: never;
804 };
805 get?: never;
806 put?: never;
807 /**
808 * Expand a short prompt into a structured legal prompt
809 * @description Invokes the ``enhance-prompt`` skill against the gateway (with
810 * ``lq_ai_skills=['enhance-prompt']`` so user/team-scope
811 * shadows of the skill are honored per the D8.1b resolver).
812 * Returns the structured expansion the SKILL.md output schema
813 * produces — ``expansion_applied`` + ``expanded_prompt`` +
814 * ``reasoning`` + ``skip_reason`` + ``preview_to_user`` — plus
815 * an ``interaction_id`` the frontend uses to PATCH ``used`` /
816 * ``edited_before_use`` after the user acts on the preview.
817 *
818 * Defaults to the ``fast`` model alias (cheaper/smaller than
819 * ``smart`` per the spec's "smaller/cheaper model" guidance);
820 * ``model`` on the body overrides per-request.
821 *
822 * When the model produces malformed structured output, the
823 * response carries ``expansion_applied=false`` +
824 * ``skip_reason='parse_error'`` rather than 500 — the frontend
825 * falls back to submitting the original prompt.
826 */
827 post: {
828 parameters: {
829 query?: never;
830 header?: never;
831 path?: never;
832 cookie?: never;
833 };
834 requestBody: {
835 content: {
836 "application/json": components["schemas"]["EnhancePromptRequest"];
837 };
838 };
839 responses: {
840 /** @description Expansion (or a structured skip decision) */
841 200: {
842 headers: {
843 [name: string]: unknown;
844 };
845 content: {
846 "application/json": components["schemas"]["EnhancePromptResponse"];
847 };
848 };
849 /** @description Gateway / provider failure during enhancement */
850 502: {
851 headers: {
852 [name: string]: unknown;
853 };
854 content: {
855 "application/json": components["schemas"]["Error"];
856 };
857 };
858 };
859 };
860 delete?: never;
861 options?: never;
862 head?: never;
863 patch?: never;
864 trace?: never;
865 };
866 "/api/v1/enhance-prompt/{interaction_id}": {
867 parameters: {
868 query?: never;
869 header?: never;
870 path: {
871 interaction_id: string;
872 };
873 cookie?: never;
874 };
875 get?: never;
876 put?: never;
877 post?: never;
878 delete?: never;
879 options?: never;
880 head?: never;
881 /**
882 * Record what the user did with the enhancement preview
883 * @description Updates ``used`` and ``edited_before_use`` for telemetry.
884 * Owner-only (404 if the row belongs to another user — same
885 * id-probing posture as user_skills + chats). Idempotent: a
886 * no-op PATCH returns 200 without writing.
887 */
888 patch: {
889 parameters: {
890 query?: never;
891 header?: never;
892 path: {
893 interaction_id: string;
894 };
895 cookie?: never;
896 };
897 requestBody: {
898 content: {
899 "application/json": components["schemas"]["EnhancePromptOutcomeUpdate"];
900 };
901 };
902 responses: {
903 /** @description Updated interaction */
904 200: {
905 headers: {
906 [name: string]: unknown;
907 };
908 content: {
909 "application/json": components["schemas"]["EnhancePromptResponse"];
910 };
911 };
912 /** @description Interaction not found OR not owned by the caller. */
913 404: {
914 headers: {
915 [name: string]: unknown;
916 };
917 content: {
918 "application/json": components["schemas"]["Error"];
919 };
920 };
921 };
922 };
923 trace?: never;
924 };
925 "/api/v1/projects": {
926 parameters: {
927 query?: never;
928 header?: never;
929 path?: never;
930 cookie?: never;
931 };
932 /**
933 * List the caller's projects
934 * @description Returns the caller's active projects by default. ``archived=true``
935 * returns archived projects only; ``archived=false`` is equivalent
936 * to omitting the parameter (active only). Per-user isolation:
937 * only the caller's own projects are returned.
938 */
939 get: {
940 parameters: {
941 query?: {
942 /** @description When true, return only archived projects. */
943 archived?: boolean;
944 };
945 header?: never;
946 path?: never;
947 cookie?: never;
948 };
949 requestBody?: never;
950 responses: {
951 /** @description List of projects (active or archived per the filter). */
952 200: {
953 headers: {
954 [name: string]: unknown;
955 };
956 content: {
957 "application/json": components["schemas"]["Project"][];
958 };
959 };
960 };
961 };
962 put?: never;
963 /**
964 * Create a project
965 * @description Creates a project owned by the caller. ``slug`` is generated
966 * from ``name`` if omitted; collisions with the caller's existing
967 * active projects resolve with a numeric suffix (``-2``, ``-3``,
968 * ...). Setting ``privileged=true`` requires
969 * ``minimum_inference_tier`` to be set; missing-tier returns 422.
970 */
971 post: {
972 parameters: {
973 query?: never;
974 header?: never;
975 path?: never;
976 cookie?: never;
977 };
978 requestBody: {
979 content: {
980 "application/json": components["schemas"]["ProjectCreate"];
981 };
982 };
983 responses: {
984 /** @description Project created */
985 201: {
986 headers: {
987 [name: string]: unknown;
988 };
989 content: {
990 "application/json": components["schemas"]["Project"];
991 };
992 };
993 /** @description Slug collision under concurrent create */
994 409: {
995 headers: {
996 [name: string]: unknown;
997 };
998 content: {
999 "application/json": components["schemas"]["Error"];
1000 };
1001 };
1002 /** @description Schema validation failure (e.g., privileged-without-tier) */
1003 422: {
1004 headers: {
1005 [name: string]: unknown;
1006 };
1007 content: {
1008 "application/json": components["schemas"]["Error"];
1009 };
1010 };
1011 };
1012 };
1013 delete?: never;
1014 options?: never;
1015 head?: never;
1016 patch?: never;
1017 trace?: never;
1018 };
1019 "/api/v1/projects/{project_id}": {
1020 parameters: {
1021 query?: never;
1022 header?: never;
1023 path: {
1024 project_id: string;
1025 };
1026 cookie?: never;
1027 };
1028 /**
1029 * Fetch a single project
1030 * @description Returns the canonical ``Project`` shape with ``attached_file_ids``
1031 * and ``attached_skill_names`` populated from the join tables.
1032 * Archived projects are visible via direct GET so the client can
1033 * render an archived-detail page; the list endpoint excludes them
1034 * by default.
1035 */
1036 get: {
1037 parameters: {
1038 query?: never;
1039 header?: never;
1040 path: {
1041 project_id: string;
1042 };
1043 cookie?: never;
1044 };
1045 requestBody?: never;
1046 responses: {
1047 /** @description Project */
1048 200: {
1049 headers: {
1050 [name: string]: unknown;
1051 };
1052 content: {
1053 "application/json": components["schemas"]["Project"];
1054 };
1055 };
1056 /** @description Not found (or owned by another user) */
1057 404: {
1058 headers: {
1059 [name: string]: unknown;
1060 };
1061 content: {
1062 "application/json": components["schemas"]["Error"];
1063 };
1064 };
1065 };
1066 };
1067 put?: never;
1068 post?: never;
1069 /**
1070 * Soft-delete (archive) a project
1071 * @description Sets ``archived_at`` on the row. Hard-delete is owned by D6.
1072 * Idempotent: a second DELETE on an already-archived project
1073 * returns 404.
1074 */
1075 delete: {
1076 parameters: {
1077 query?: never;
1078 header?: never;
1079 path: {
1080 project_id: string;
1081 };
1082 cookie?: never;
1083 };
1084 requestBody?: never;
1085 responses: {
1086 /** @description Project archived */
1087 204: {
1088 headers: {
1089 [name: string]: unknown;
1090 };
1091 content?: never;
1092 };
1093 /** @description Not found, or already archived */
1094 404: {
1095 headers: {
1096 [name: string]: unknown;
1097 };
1098 content: {
1099 "application/json": components["schemas"]["Error"];
1100 };
1101 };
1102 };
1103 };
1104 options?: never;
1105 head?: never;
1106 /**
1107 * Partial update of a project
1108 * @description Applies only the fields the caller sets. The
1109 * ``privileged``↔``minimum_inference_tier`` rule is re-checked
1110 * against the *merged* state — setting either alone in a way that
1111 * would leave the project privileged-but-tierless returns 400.
1112 * ``archived: true`` archives the project (equivalent to DELETE);
1113 * ``archived: false`` unarchives it.
1114 */
1115 patch: {
1116 parameters: {
1117 query?: never;
1118 header?: never;
1119 path: {
1120 project_id: string;
1121 };
1122 cookie?: never;
1123 };
1124 requestBody: {
1125 content: {
1126 "application/json": components["schemas"]["ProjectUpdate"];
1127 };
1128 };
1129 responses: {
1130 /** @description Project updated */
1131 200: {
1132 headers: {
1133 [name: string]: unknown;
1134 };
1135 content: {
1136 "application/json": components["schemas"]["Project"];
1137 };
1138 };
1139 /** @description Cross-field rule violation (e.g., privileged-without-tier) */
1140 400: {
1141 headers: {
1142 [name: string]: unknown;
1143 };
1144 content: {
1145 "application/json": components["schemas"]["Error"];
1146 };
1147 };
1148 /** @description Not found (or owned by another user) */
1149 404: {
1150 headers: {
1151 [name: string]: unknown;
1152 };
1153 content: {
1154 "application/json": components["schemas"]["Error"];
1155 };
1156 };
1157 };
1158 };
1159 trace?: never;
1160 };
1161 "/api/v1/projects/{project_id}/skills": {
1162 parameters: {
1163 query?: never;
1164 header?: never;
1165 path: {
1166 project_id: string;
1167 };
1168 cookie?: never;
1169 };
1170 get?: never;
1171 put?: never;
1172 /**
1173 * Attach a skill to the project
1174 * @description Attaches a registry-known skill to the project by name. The
1175 * skill must exist in the in-memory skill registry (C1); unknown
1176 * names return 404. Re-attaching an already-attached skill
1177 * returns 409.
1178 */
1179 post: {
1180 parameters: {
1181 query?: never;
1182 header?: never;
1183 path: {
1184 project_id: string;
1185 };
1186 cookie?: never;
1187 };
1188 requestBody: {
1189 content: {
1190 "application/json": {
1191 skill_name: string;
1192 };
1193 };
1194 };
1195 responses: {
1196 /** @description Attached */
1197 204: {
1198 headers: {
1199 [name: string]: unknown;
1200 };
1201 content?: never;
1202 };
1203 /** @description Project or skill not found */
1204 404: {
1205 headers: {
1206 [name: string]: unknown;
1207 };
1208 content: {
1209 "application/json": components["schemas"]["Error"];
1210 };
1211 };
1212 /** @description Skill already attached */
1213 409: {
1214 headers: {
1215 [name: string]: unknown;
1216 };
1217 content: {
1218 "application/json": components["schemas"]["Error"];
1219 };
1220 };
1221 };
1222 };
1223 delete?: never;
1224 options?: never;
1225 head?: never;
1226 patch?: never;
1227 trace?: never;
1228 };
1229 "/api/v1/projects/{project_id}/skills/{skill_name}": {
1230 parameters: {
1231 query?: never;
1232 header?: never;
1233 path: {
1234 project_id: string;
1235 skill_name: string;
1236 };
1237 cookie?: never;
1238 };
1239 get?: never;
1240 put?: never;
1241 post?: never;
1242 /**
1243 * Detach a skill from the project
1244 * @description Removes the project↔skill join row. The skill itself is
1245 * registry-canonical and untouched. Detaching a skill that is
1246 * not attached returns 404 (idempotency-violating; clients
1247 * should treat 204 and 404 as terminal success states).
1248 */
1249 delete: {
1250 parameters: {
1251 query?: never;
1252 header?: never;
1253 path: {
1254 project_id: string;
1255 skill_name: string;
1256 };
1257 cookie?: never;
1258 };
1259 requestBody?: never;
1260 responses: {
1261 /** @description Detached */
1262 204: {
1263 headers: {
1264 [name: string]: unknown;
1265 };
1266 content?: never;
1267 };
1268 /** @description Project or attachment not found */
1269 404: {
1270 headers: {
1271 [name: string]: unknown;
1272 };
1273 content: {
1274 "application/json": components["schemas"]["Error"];
1275 };
1276 };
1277 };
1278 };
1279 options?: never;
1280 head?: never;
1281 patch?: never;
1282 trace?: never;
1283 };
1284 "/api/v1/projects/{project_id}/files": {
1285 parameters: {
1286 query?: never;
1287 header?: never;
1288 path: {
1289 project_id: string;
1290 };
1291 cookie?: never;
1292 };
1293 get?: never;
1294 put?: never;
1295 /**
1296 * Attach an uploaded file to the project
1297 * @description Attaches an uploaded file to the project. The caller must own
1298 * both the project and the file (cross-user → 404 on either).
1299 * Re-attaching an already-attached file returns 409.
1300 */
1301 post: {
1302 parameters: {
1303 query?: never;
1304 header?: never;
1305 path: {
1306 project_id: string;
1307 };
1308 cookie?: never;
1309 };
1310 requestBody: {
1311 content: {
1312 "application/json": {
1313 /** Format: uuid */
1314 file_id: string;
1315 };
1316 };
1317 };
1318 responses: {
1319 /** @description Attached */
1320 204: {
1321 headers: {
1322 [name: string]: unknown;
1323 };
1324 content?: never;
1325 };
1326 /** @description Project or file not found */
1327 404: {
1328 headers: {
1329 [name: string]: unknown;
1330 };
1331 content: {
1332 "application/json": components["schemas"]["Error"];
1333 };
1334 };
1335 /** @description File already attached */
1336 409: {
1337 headers: {
1338 [name: string]: unknown;
1339 };
1340 content: {
1341 "application/json": components["schemas"]["Error"];
1342 };
1343 };
1344 };
1345 };
1346 delete?: never;
1347 options?: never;
1348 head?: never;
1349 patch?: never;
1350 trace?: never;
1351 };
1352 "/api/v1/projects/{project_id}/files/{file_id}": {
1353 parameters: {
1354 query?: never;
1355 header?: never;
1356 path: {
1357 project_id: string;
1358 file_id: string;
1359 };
1360 cookie?: never;
1361 };
1362 get?: never;
1363 put?: never;
1364 post?: never;
1365 /**
1366 * Detach a file from the project
1367 * @description Removes the project↔file join row. The file row itself is
1368 * untouched (use ``DELETE /api/v1/files/{file_id}`` to soft-
1369 * delete the file). Detaching a file that is not attached
1370 * returns 404.
1371 */
1372 delete: {
1373 parameters: {
1374 query?: never;
1375 header?: never;
1376 path: {
1377 project_id: string;
1378 file_id: string;
1379 };
1380 cookie?: never;
1381 };
1382 requestBody?: never;
1383 responses: {
1384 /** @description Detached */
1385 204: {
1386 headers: {
1387 [name: string]: unknown;
1388 };
1389 content?: never;
1390 };
1391 /** @description Project or attachment not found */
1392 404: {
1393 headers: {
1394 [name: string]: unknown;
1395 };
1396 content: {
1397 "application/json": components["schemas"]["Error"];
1398 };
1399 };
1400 };
1401 };
1402 options?: never;
1403 head?: never;
1404 patch?: never;
1405 trace?: never;
1406 };
1407 "/api/v1/projects/sandbox/ensure": {
1408 parameters: {
1409 query?: never;
1410 header?: never;
1411 path?: never;
1412 cookie?: never;
1413 };
1414 get?: never;
1415 put?: never;
1416 /**
1417 * Find or create the caller's try-it sandbox matter (Wave D.2)
1418 * @description Idempotent find-or-create for the per-user *try-it sandbox*
1419 * project. The sandbox is a system-managed matter (slug
1420 * ``__sandbox__``, ``is_sandbox=true``) used to scope skill try-it
1421 * conversations that should not count toward billable matter
1422 * activity.
1423 *
1424 * * First call returns 201 with a fresh row.
1425 * * Subsequent calls return 200 with the same row.
1426 * * If the sandbox was previously soft-deleted, the next ensure
1427 * call recreates it (returns 201).
1428 *
1429 * Concurrent callers are safe: the ``ON CONFLICT DO NOTHING`` path
1430 * ensures only one row is ever created per owner.
1431 */
1432 post: {
1433 parameters: {
1434 query?: never;
1435 header?: never;
1436 path?: never;
1437 cookie?: never;
1438 };
1439 requestBody?: never;
1440 responses: {
1441 /** @description Existing sandbox (already existed) */
1442 200: {
1443 headers: {
1444 [name: string]: unknown;
1445 };
1446 content: {
1447 "application/json": components["schemas"]["Project"];
1448 };
1449 };
1450 /** @description Sandbox created */
1451 201: {
1452 headers: {
1453 [name: string]: unknown;
1454 };
1455 content: {
1456 "application/json": components["schemas"]["Project"];
1457 };
1458 };
1459 };
1460 };
1461 delete?: never;
1462 options?: never;
1463 head?: never;
1464 patch?: never;
1465 trace?: never;
1466 };
1467 "/api/v1/chats/search": {
1468 parameters: {
1469 query?: never;
1470 header?: never;
1471 path?: never;
1472 cookie?: never;
1473 };
1474 /**
1475 * Full-text search across chats + messages (PRD §1.7)
1476 * @description Wave B. Postgres ``websearch_to_tsquery`` against the
1477 * ``chats.title_tsv`` + ``messages.content_tsv`` generated
1478 * columns (migration 0016). Owner-scoped; archived chats are
1479 * excluded. Returns ranked hits with a ``ts_headline`` snippet
1480 * of the matching message (or the title itself for title hits).
1481 */
1482 get: {
1483 parameters: {
1484 query: {
1485 q: string;
1486 limit?: number;
1487 };
1488 header?: never;
1489 path?: never;
1490 cookie?: never;
1491 };
1492 requestBody?: never;
1493 responses: {
1494 /** @description Ranked search hits */
1495 200: {
1496 headers: {
1497 [name: string]: unknown;
1498 };
1499 content: {
1500 "application/json": components["schemas"]["ChatSearchResponse"];
1501 };
1502 };
1503 };
1504 };
1505 put?: never;
1506 post?: never;
1507 delete?: never;
1508 options?: never;
1509 head?: never;
1510 patch?: never;
1511 trace?: never;
1512 };
1513 "/api/v1/chats": {
1514 parameters: {
1515 query?: never;
1516 header?: never;
1517 path?: never;
1518 cookie?: never;
1519 };
1520 /** List the caller's chats (cursor-paginated) */
1521 get: {
1522 parameters: {
1523 query?: {
1524 /** @description Filter to chats inside a specific project. */
1525 project_id?: string;
1526 /** @description When true, return archived chats only. Default excludes archived. */
1527 archived?: boolean;
1528 /** @description Opaque cursor from a previous page's `next_cursor`. */
1529 cursor?: string;
1530 limit?: number;
1531 };
1532 header?: never;
1533 path?: never;
1534 cookie?: never;
1535 };
1536 requestBody?: never;
1537 responses: {
1538 /** @description Paginated chats */
1539 200: {
1540 headers: {
1541 [name: string]: unknown;
1542 };
1543 content: {
1544 "application/json": {
1545 items: components["schemas"]["Chat"][];
1546 next_cursor: string | null;
1547 };
1548 };
1549 };
1550 };
1551 };
1552 put?: never;
1553 /** Create a new chat */
1554 post: {
1555 parameters: {
1556 query?: never;
1557 header?: never;
1558 path?: never;
1559 cookie?: never;
1560 };
1561 requestBody: {
1562 content: {
1563 "application/json": components["schemas"]["ChatCreate"];
1564 };
1565 };
1566 responses: {
1567 /** @description Chat created */
1568 201: {
1569 headers: {
1570 [name: string]: unknown;
1571 };
1572 content: {
1573 "application/json": components["schemas"]["Chat"];
1574 };
1575 };
1576 };
1577 };
1578 delete?: never;
1579 options?: never;
1580 head?: never;
1581 patch?: never;
1582 trace?: never;
1583 };
1584 "/api/v1/chats/{chat_id}": {
1585 parameters: {
1586 query?: never;
1587 header?: never;
1588 path: {
1589 chat_id: string;
1590 };
1591 cookie?: never;
1592 };
1593 /** Fetch a single chat (archived rows are visible) */
1594 get: {
1595 parameters: {
1596 query?: never;
1597 header?: never;
1598 path: {
1599 chat_id: string;
1600 };
1601 cookie?: never;
1602 };
1603 requestBody?: never;
1604 responses: {
1605 /** @description Chat */
1606 200: {
1607 headers: {
1608 [name: string]: unknown;
1609 };
1610 content: {
1611 "application/json": components["schemas"]["Chat"];
1612 };
1613 };
1614 /** @description Chat does not exist or is owned by a different user */
1615 404: {
1616 headers: {
1617 [name: string]: unknown;
1618 };
1619 content: {
1620 "application/json": components["schemas"]["Error"];
1621 };
1622 };
1623 };
1624 };
1625 put?: never;
1626 post?: never;
1627 /** Soft-delete the chat (sets `archived_at`) */
1628 delete: {
1629 parameters: {
1630 query?: never;
1631 header?: never;
1632 path: {
1633 chat_id: string;
1634 };
1635 cookie?: never;
1636 };
1637 requestBody?: never;
1638 responses: {
1639 /** @description Chat archived */
1640 204: {
1641 headers: {
1642 [name: string]: unknown;
1643 };
1644 content?: never;
1645 };
1646 /** @description Chat already archived or does not exist */
1647 404: {
1648 headers: {
1649 [name: string]: unknown;
1650 };
1651 content: {
1652 "application/json": components["schemas"]["Error"];
1653 };
1654 };
1655 };
1656 };
1657 options?: never;
1658 head?: never;
1659 /** Partial update of a chat (title or archived flag) */
1660 patch: {
1661 parameters: {
1662 query?: never;
1663 header?: never;
1664 path: {
1665 chat_id: string;
1666 };
1667 cookie?: never;
1668 };
1669 requestBody: {
1670 content: {
1671 "application/json": components["schemas"]["ChatUpdate"];
1672 };
1673 };
1674 responses: {
1675 /** @description Chat updated */
1676 200: {
1677 headers: {
1678 [name: string]: unknown;
1679 };
1680 content: {
1681 "application/json": components["schemas"]["Chat"];
1682 };
1683 };
1684 /** @description Chat does not exist or is owned by a different user */
1685 404: {
1686 headers: {
1687 [name: string]: unknown;
1688 };
1689 content: {
1690 "application/json": components["schemas"]["Error"];
1691 };
1692 };
1693 };
1694 };
1695 trace?: never;
1696 };
1697 "/api/v1/chats/{chat_id}/messages": {
1698 parameters: {
1699 query?: never;
1700 header?: never;
1701 path: {
1702 chat_id: string;
1703 };
1704 cookie?: never;
1705 };
1706 /** List messages in chat (cursor-paginated, oldest-first) */
1707 get: {
1708 parameters: {
1709 query?: {
1710 /** @description Opaque cursor from a previous page's `next_cursor`. */
1711 cursor?: string;
1712 limit?: number;
1713 };
1714 header?: never;
1715 path: {
1716 chat_id: string;
1717 };
1718 cookie?: never;
1719 };
1720 requestBody?: never;
1721 responses: {
1722 /** @description Paginated messages */
1723 200: {
1724 headers: {
1725 [name: string]: unknown;
1726 };
1727 content: {
1728 "application/json": {
1729 items: components["schemas"]["Message"][];
1730 next_cursor: string | null;
1731 };
1732 };
1733 };
1734 };
1735 };
1736 put?: never;
1737 /**
1738 * Post a user message and get the model response
1739 * @description Posts a user message and returns the assistant response. The
1740 * request's `stream` field selects between two response shapes:
1741 *
1742 * * `stream: false` (default) → JSON response with the persisted
1743 * assistant message, the routed Inference Tier, and routing
1744 * metadata.
1745 * * `stream: true` → Server-Sent Events stream:
1746 * 1. The opening `start` frame carries `lq_ai_message_id`
1747 * (the persisted assistant message id) so clients can
1748 * poll the row later.
1749 * 2. Each `delta` frame carries `lq_ai_message_id`,
1750 * `routed_inference_tier`, and `applied_skills` per
1751 * ADR 0007.
1752 * 3. The terminal `complete` frame (success) or `Error`
1753 * envelope (mid-stream failure) precedes the OpenAI-style
1754 * `data: [DONE]` line.
1755 *
1756 * **C3 persistence.** The backend writes the user message row
1757 * first (unconditionally), generates the assistant message UUID,
1758 * forwards it to the gateway as `lq_ai_message_id` so the
1759 * gateway's `inference_routing_log` row carries the same id, and
1760 * persists the assistant row at end-of-stream (or end of the
1761 * non-streaming response). On streaming failure the assistant
1762 * row is persisted with whatever content was received and
1763 * `error_code` populated for audit.
1764 *
1765 * Citations are an empty array until M2's citation engine ships.
1766 *
1767 * The response also surfaces the routed Inference Tier in the
1768 * `X-LQ-AI-Routed-Inference-Tier` HTTP header (header-only
1769 * consumers don't need to parse the body).
1770 */
1771 post: {
1772 parameters: {
1773 query?: never;
1774 header?: never;
1775 path: {
1776 chat_id: string;
1777 };
1778 cookie?: never;
1779 };
1780 requestBody: {
1781 content: {
1782 "application/json": components["schemas"]["MessageCreate"];
1783 };
1784 };
1785 responses: {
1786 /** @description Either a JSON response or an SSE stream depending on `stream` */
1787 200: {
1788 headers: {
1789 /** @description Routed Inference Tier — duplicates the body field for header-only consumers */
1790 "X-LQ-AI-Routed-Inference-Tier"?: 1 | 2 | 3 | 4 | 5;
1791 /** @description Provider that handled the request (set by gateway) */
1792 "X-LQ-AI-Routed-Provider"?: string;
1793 [name: string]: unknown;
1794 };
1795 content: {
1796 "application/json": components["schemas"]["MessagePostResponse"];
1797 "text/event-stream": components["schemas"]["MessageStreamEvent"];
1798 };
1799 };
1800 /** @description Invalid request (bad chat_id, empty content, malformed body) */
1801 400: {
1802 headers: {
1803 [name: string]: unknown;
1804 };
1805 content: {
1806 "application/json": components["schemas"]["Error"];
1807 };
1808 };
1809 /** @description Missing or invalid bearer token */
1810 401: {
1811 headers: {
1812 [name: string]: unknown;
1813 };
1814 content: {
1815 "application/json": components["schemas"]["Error"];
1816 };
1817 };
1818 /** @description Forced password change required (B2 gate) or tier-floor refusal (D1) */
1819 403: {
1820 headers: {
1821 [name: string]: unknown;
1822 };
1823 content: {
1824 "application/json": components["schemas"]["Error"];
1825 };
1826 };
1827 /** @description Gateway returned an upstream error (provider_unavailable, etc.) */
1828 502: {
1829 headers: {
1830 [name: string]: unknown;
1831 };
1832 content: {
1833 "application/json": components["schemas"]["Error"];
1834 };
1835 };
1836 /** @description Gateway unreachable (network failure or 5xx) */
1837 503: {
1838 headers: {
1839 [name: string]: unknown;
1840 };
1841 content: {
1842 "application/json": components["schemas"]["Error"];
1843 };
1844 };
1845 /** @description Gateway request timed out */
1846 504: {
1847 headers: {
1848 [name: string]: unknown;
1849 };
1850 content: {
1851 "application/json": components["schemas"]["Error"];
1852 };
1853 };
1854 };
1855 };
1856 delete?: never;
1857 options?: never;
1858 head?: never;
1859 patch?: never;
1860 trace?: never;
1861 };
1862 "/api/v1/chats/{chat_id}/messages/{message_id}/citations": {
1863 parameters: {
1864 query?: never;
1865 header?: never;
1866 path: {
1867 chat_id: string;
1868 message_id: string;
1869 };
1870 cookie?: never;
1871 };
1872 /** Get citations for a message (resolves to source documents) */
1873 get: {
1874 parameters: {
1875 query?: never;
1876 header?: never;
1877 path: {
1878 chat_id: string;
1879 message_id: string;
1880 };
1881 cookie?: never;
1882 };
1883 requestBody?: never;
1884 responses: {
1885 /** @description Citations */
1886 200: {
1887 headers: {
1888 [name: string]: unknown;
1889 };
1890 content: {
1891 "application/json": components["schemas"]["Citation"][];
1892 };
1893 };
1894 };
1895 };
1896 put?: never;
1897 post?: never;
1898 delete?: never;
1899 options?: never;
1900 head?: never;
1901 patch?: never;
1902 trace?: never;
1903 };
1904 "/api/v1/chats/{chat_id}/messages/{message_id}/sources": {
1905 parameters: {
1906 query?: never;
1907 header?: never;
1908 path: {
1909 chat_id: string;
1910 message_id: string;
1911 };
1912 cookie?: never;
1913 };
1914 /** Get external-source provenance (case law consulted) for a message (PR6c) */
1915 get: {
1916 parameters: {
1917 query?: never;
1918 header?: never;
1919 path: {
1920 chat_id: string;
1921 message_id: string;
1922 };
1923 cookie?: never;
1924 };
1925 requestBody?: never;
1926 responses: {
1927 /** @description External sources consulted during the message turn */
1928 200: {
1929 headers: {
1930 [name: string]: unknown;
1931 };
1932 content: {
1933 "application/json": {
1934 /** Format: uuid */
1935 id?: string;
1936 /** Format: uuid */
1937 message_id?: string;
1938 source_kind?: string;
1939 label?: string;
1940 subtitle?: string | null;
1941 url?: string | null;
1942 external_ref?: string | null;
1943 provider?: string;
1944 tool?: string;
1945 /** Format: date-time */
1946 created_at?: string;
1947 }[];
1948 };
1949 };
1950 };
1951 };
1952 put?: never;
1953 post?: never;
1954 delete?: never;
1955 options?: never;
1956 head?: never;
1957 patch?: never;
1958 trace?: never;
1959 };
1960 "/api/v1/skills": {
1961 parameters: {
1962 query?: never;
1963 header?: never;
1964 path?: never;
1965 cookie?: never;
1966 };
1967 /** List available skills */
1968 get: {
1969 parameters: {
1970 query?: {
1971 scope?: "builtin" | "user" | "team" | "all";
1972 tag?: string;
1973 };
1974 header?: never;
1975 path?: never;
1976 cookie?: never;
1977 };
1978 requestBody?: never;
1979 responses: {
1980 /** @description Skills */
1981 200: {
1982 headers: {
1983 [name: string]: unknown;
1984 };
1985 content: {
1986 "application/json": components["schemas"]["SkillSummary"][];
1987 };
1988 };
1989 };
1990 };
1991 put?: never;
1992 post?: never;
1993 delete?: never;
1994 options?: never;
1995 head?: never;
1996 patch?: never;
1997 trace?: never;
1998 };
1999 "/api/v1/skills/{skill_name}": {
2000 parameters: {
2001 query?: never;
2002 header?: never;
2003 path: {
2004 skill_name: string;
2005 };
2006 cookie?: never;
2007 };
2008 /** Get skill details (frontmatter + body + reference files) */
2009 get: {
2010 parameters: {
2011 query?: never;
2012 header?: never;
2013 path: {
2014 skill_name: string;
2015 };
2016 cookie?: never;
2017 };
2018 requestBody?: never;
2019 responses: {
2020 /** @description Skill */
2021 200: {
2022 headers: {
2023 [name: string]: unknown;
2024 };
2025 content: {
2026 "application/json": components["schemas"]["Skill"];
2027 };
2028 };
2029 /** @description No skill with that name is in the registry. */
2030 404: {
2031 headers: {
2032 [name: string]: unknown;
2033 };
2034 content: {
2035 "application/json": components["schemas"]["Error"];
2036 };
2037 };
2038 };
2039 };
2040 put?: never;
2041 post?: never;
2042 delete?: never;
2043 options?: never;
2044 head?: never;
2045 patch?: never;
2046 trace?: never;
2047 };
2048 "/api/v1/skills/{skill_name}/contents": {
2049 parameters: {
2050 query?: never;
2051 header?: never;
2052 path: {
2053 skill_name: string;
2054 };
2055 cookie?: never;
2056 };
2057 /**
2058 * Full skill contents for the skill inspector (PRD §3.4 — Wave A)
2059 * @description Returns the same payload shape as ``GET /skills/{skill_name}``
2060 * (SKILL.md frontmatter + body + reference + example files). The
2061 * dedicated URL exists because PRD §3.4 names it explicitly as
2062 * the contract behind the "view this skill" affordance + the
2063 * skill inspector side panel. Applies the D8.1b resolution stack
2064 * (user > team > built-in).
2065 */
2066 get: {
2067 parameters: {
2068 query?: never;
2069 header?: never;
2070 path: {
2071 skill_name: string;
2072 };
2073 cookie?: never;
2074 };
2075 requestBody?: never;
2076 responses: {
2077 /** @description Skill (same shape as the base GET) */
2078 200: {
2079 headers: {
2080 [name: string]: unknown;
2081 };
2082 content: {
2083 "application/json": components["schemas"]["Skill"];
2084 };
2085 };
2086 /** @description No skill with that name resolves for the caller. */
2087 404: {
2088 headers: {
2089 [name: string]: unknown;
2090 };
2091 content: {
2092 "application/json": components["schemas"]["Error"];
2093 };
2094 };
2095 };
2096 };
2097 put?: never;
2098 post?: never;
2099 delete?: never;
2100 options?: never;
2101 head?: never;
2102 patch?: never;
2103 trace?: never;
2104 };
2105 "/api/v1/skills/{skill_name}/inputs": {
2106 parameters: {
2107 query?: never;
2108 header?: never;
2109 path: {
2110 skill_name: string;
2111 };
2112 cookie?: never;
2113 };
2114 /**
2115 * Declared inputs (form schema) for the skill (PRD §3.4 — Wave A)
2116 * @description The PRD §3.4 skill-input-form pattern: skills declare inputs
2117 * in their frontmatter so the UI can render a structured form
2118 * rather than letting the model ask for missing context
2119 * conversationally. The endpoint resolves user > team > built-in
2120 * and looks for the inputs block at either the top of the
2121 * frontmatter (formal-guide shape) or under ``lq_ai.inputs``
2122 * (corpus reality for skills like enhance-prompt). Returns a
2123 * name-only stub when the skill declares no inputs.
2124 */
2125 get: {
2126 parameters: {
2127 query?: never;
2128 header?: never;
2129 path: {
2130 skill_name: string;
2131 };
2132 cookie?: never;
2133 };
2134 requestBody?: never;
2135 responses: {
2136 /** @description Inputs (required + optional) */
2137 200: {
2138 headers: {
2139 [name: string]: unknown;
2140 };
2141 content: {
2142 "application/json": components["schemas"]["SkillInputs"];
2143 };
2144 };
2145 /** @description No skill with that name resolves for the caller. */
2146 404: {
2147 headers: {
2148 [name: string]: unknown;
2149 };
2150 content: {
2151 "application/json": components["schemas"]["Error"];
2152 };
2153 };
2154 };
2155 };
2156 put?: never;
2157 post?: never;
2158 delete?: never;
2159 options?: never;
2160 head?: never;
2161 patch?: never;
2162 trace?: never;
2163 };
2164 "/api/v1/skills/{skill_name}/fork": {
2165 parameters: {
2166 query?: never;
2167 header?: never;
2168 path: {
2169 skill_name: string;
2170 };
2171 cookie?: never;
2172 };
2173 get?: never;
2174 put?: never;
2175 /**
2176 * Fork a built-in skill into the caller's user scope (D8)
2177 * @description Copies the built-in's resolved frontmatter and body into a new
2178 * ``user_skills`` row owned by the caller (ADR 0012). The request
2179 * body's ``new_name`` becomes the new row's slug (omitted →
2180 * defaults to the source slug, which produces a same-slug shadow);
2181 * ``scope`` MUST be ``user`` in D8 — ``team`` is reserved for
2182 * D8.1 and returns 400.
2183 */
2184 post: {
2185 parameters: {
2186 query?: never;
2187 header?: never;
2188 path: {
2189 skill_name: string;
2190 };
2191 cookie?: never;
2192 };
2193 requestBody?: {
2194 content: {
2195 "application/json": {
2196 /** @description New slug for the user-scope row */
2197 new_name?: string;
2198 /**
2199 * @default user
2200 * @enum {string}
2201 */
2202 scope?: "user" | "team";
2203 };
2204 };
2205 };
2206 responses: {
2207 /** @description Fork created */
2208 201: {
2209 headers: {
2210 [name: string]: unknown;
2211 };
2212 content: {
2213 "application/json": components["schemas"]["Skill"];
2214 };
2215 };
2216 /** @description ``scope=team`` requested (deferred to D8.1). */
2217 400: {
2218 headers: {
2219 [name: string]: unknown;
2220 };
2221 content: {
2222 "application/json": components["schemas"]["Error"];
2223 };
2224 };
2225 /** @description A user-scope skill with that slug already exists for this user. */
2226 409: {
2227 headers: {
2228 [name: string]: unknown;
2229 };
2230 content: {
2231 "application/json": components["schemas"]["Error"];
2232 };
2233 };
2234 };
2235 };
2236 delete?: never;
2237 options?: never;
2238 head?: never;
2239 patch?: never;
2240 trace?: never;
2241 };
2242 "/api/v1/skills/autocomplete": {
2243 parameters: {
2244 query?: never;
2245 header?: never;
2246 path?: never;
2247 cookie?: never;
2248 };
2249 /**
2250 * Typeahead for the chat composer's skill picker (Wave D.2)
2251 * @description Two modes based on the ``q`` query parameter:
2252 *
2253 * * **Empty ``q``** — returns the caller's most-recently-used skills
2254 * (by ``messages.applied_skills``), filled out alphabetically to
2255 * ``limit`` when recents are fewer than ``limit``.
2256 * * **Non-empty ``q``** — ranks the merged catalog by three signals
2257 * (slash-alias prefix > slug prefix > title substring) and returns
2258 * up to ``limit`` non-zero matches.
2259 *
2260 * Shadowing: a user-scope row at the same slug as a built-in hides
2261 * the built-in (ADR 0012). ``scope`` on each result distinguishes
2262 * user shadows from built-ins.
2263 *
2264 * ``limit`` is hard-clamped at 25 — a request for ``limit=50``
2265 * returns 422 rather than silently truncating.
2266 */
2267 get: {
2268 parameters: {
2269 query?: {
2270 /** @description Substring to match. Empty returns recents. */
2271 q?: string;
2272 limit?: number;
2273 };
2274 header?: never;
2275 path?: never;
2276 cookie?: never;
2277 };
2278 requestBody?: never;
2279 responses: {
2280 /** @description Autocomplete results (may be empty) */
2281 200: {
2282 headers: {
2283 [name: string]: unknown;
2284 };
2285 content: {
2286 "application/json": {
2287 results: {
2288 slug: string;
2289 slash_alias?: string | null;
2290 title: string;
2291 description?: string | null;
2292 /** @enum {string} */
2293 scope: "builtin" | "user" | "team";
2294 icon?: string | null;
2295 }[];
2296 };
2297 };
2298 };
2299 /** @description limit out of range (must be 1–25). */
2300 422: {
2301 headers: {
2302 [name: string]: unknown;
2303 };
2304 content?: never;
2305 };
2306 };
2307 };
2308 put?: never;
2309 post?: never;
2310 delete?: never;
2311 options?: never;
2312 head?: never;
2313 patch?: never;
2314 trace?: never;
2315 };
2316 "/api/v1/user-skills": {
2317 parameters: {
2318 query?: never;
2319 header?: never;
2320 path?: never;
2321 cookie?: never;
2322 };
2323 /**
2324 * List the caller's editable skills (user-scope by default; ?scope=team|all)
2325 * @description Returns the rich ``UserSkill`` view (body + frontmatter_extra
2326 * included) for the management UI. The picker-side merge view
2327 * lives at ``GET /api/v1/skills?scope=all`` (summary shape).
2328 *
2329 * Scope filter (D8.1c — default ``user`` for back-compat):
2330 *
2331 * * ``user`` — caller's user-scope rows only.
2332 * * ``team`` — team-scope rows from teams where the caller is a
2333 * team-admin. (Non-admin members read team skills in the picker,
2334 * not here, since they can't mutate.)
2335 * * ``all`` — both layers merged + sorted by ``updated_at DESC``.
2336 */
2337 get: {
2338 parameters: {
2339 query?: {
2340 scope?: "user" | "team" | "all";
2341 };
2342 header?: never;
2343 path?: never;
2344 cookie?: never;
2345 };
2346 requestBody?: never;
2347 responses: {
2348 /** @description List of editable skill rows for the caller */
2349 200: {
2350 headers: {
2351 [name: string]: unknown;
2352 };
2353 content: {
2354 "application/json": components["schemas"]["UserSkill"][];
2355 };
2356 };
2357 };
2358 };
2359 put?: never;
2360 /**
2361 * Create a user- or team-scope skill (D8 + D8.1b)
2362 * @description Creates a new skill row. Scope branches (per ADR 0012 + D8.1b):
2363 *
2364 * * ``scope='user'`` (default) — owned by the caller. Slug
2365 * collision with the caller's existing non-archived rows
2366 * returns 409. Collision with a filesystem built-in is
2367 * **allowed** — the deliberate shadow case; the user's row
2368 * wins for their chats.
2369 * * ``scope='team'`` — owned by ``owner_team_id``. Caller must
2370 * be a team-admin of that team or 404 (id-probing-safe).
2371 * Slug collision within the team's non-archived rows returns
2372 * 409. The D8.1b resolver picks user > team > built-in.
2373 *
2374 * 422 fires when ``scope`` and ``owner_team_id`` are inconsistent.
2375 */
2376 post: {
2377 parameters: {
2378 query?: never;
2379 header?: never;
2380 path?: never;
2381 cookie?: never;
2382 };
2383 requestBody: {
2384 content: {
2385 "application/json": components["schemas"]["UserSkillCreate"];
2386 };
2387 };
2388 responses: {
2389 /** @description Created */
2390 201: {
2391 headers: {
2392 [name: string]: unknown;
2393 };
2394 content: {
2395 "application/json": components["schemas"]["UserSkill"];
2396 };
2397 };
2398 /** @description Team referenced by owner_team_id does not exist OR caller is not a team-admin (id-probing-safe). */
2399 404: {
2400 headers: {
2401 [name: string]: unknown;
2402 };
2403 content: {
2404 "application/json": components["schemas"]["Error"];
2405 };
2406 };
2407 /** @description Slug collides with the caller's user-scope rows OR the named team's team-scope rows. */
2408 409: {
2409 headers: {
2410 [name: string]: unknown;
2411 };
2412 content: {
2413 "application/json": components["schemas"]["Error"];
2414 };
2415 };
2416 /** @description scope/owner_team_id combination is invalid (team missing team id, or user carrying team id). */
2417 422: {
2418 headers: {
2419 [name: string]: unknown;
2420 };
2421 content: {
2422 "application/json": components["schemas"]["Error"];
2423 };
2424 };
2425 };
2426 };
2427 delete?: never;
2428 options?: never;
2429 head?: never;
2430 patch?: never;
2431 trace?: never;
2432 };
2433 "/api/v1/teams": {
2434 parameters: {
2435 query?: never;
2436 header?: never;
2437 path?: never;
2438 cookie?: never;
2439 };
2440 /**
2441 * List teams the caller belongs to (newest first)
2442 * @description Each row carries ``caller_role`` (admin | member) so the UI can
2443 * render mutate affordances without a second round-trip. The
2444 * optional ``?role=`` filter (D8.1c) restricts to a specific
2445 * role — the team-scope skill creation picker uses
2446 * ``?role=admin``.
2447 */
2448 get: {
2449 parameters: {
2450 query?: {
2451 role?: "admin" | "member";
2452 };
2453 header?: never;
2454 path?: never;
2455 cookie?: never;
2456 };
2457 requestBody?: never;
2458 responses: {
2459 /** @description Caller's teams (with caller_role populated) */
2460 200: {
2461 headers: {
2462 [name: string]: unknown;
2463 };
2464 content: {
2465 "application/json": components["schemas"]["TeamSummary"][];
2466 };
2467 };
2468 };
2469 };
2470 put?: never;
2471 post?: never;
2472 delete?: never;
2473 options?: never;
2474 head?: never;
2475 patch?: never;
2476 trace?: never;
2477 };
2478 "/api/v1/teams/{team_id}": {
2479 parameters: {
2480 query?: never;
2481 header?: never;
2482 path: {
2483 team_id: string;
2484 };
2485 cookie?: never;
2486 };
2487 /** Fetch a team (member-only; 404 conflates "no such team" and "not a member") */
2488 get: {
2489 parameters: {
2490 query?: never;
2491 header?: never;
2492 path: {
2493 team_id: string;
2494 };
2495 cookie?: never;
2496 };
2497 requestBody?: never;
2498 responses: {
2499 /** @description Team payload with member roster */
2500 200: {
2501 headers: {
2502 [name: string]: unknown;
2503 };
2504 content: {
2505 "application/json": components["schemas"]["Team"];
2506 };
2507 };
2508 /** @description Team does not exist OR caller is not a member. */
2509 404: {
2510 headers: {
2511 [name: string]: unknown;
2512 };
2513 content: {
2514 "application/json": components["schemas"]["Error"];
2515 };
2516 };
2517 };
2518 };
2519 put?: never;
2520 post?: never;
2521 delete?: never;
2522 options?: never;
2523 head?: never;
2524 patch?: never;
2525 trace?: never;
2526 };
2527 "/api/v1/admin/teams": {
2528 parameters: {
2529 query?: never;
2530 header?: never;
2531 path?: never;
2532 cookie?: never;
2533 };
2534 /** List every team in the deployment (admin) */
2535 get: {
2536 parameters: {
2537 query?: never;
2538 header?: never;
2539 path?: never;
2540 cookie?: never;
2541 };
2542 requestBody?: never;
2543 responses: {
2544 /** @description All teams */
2545 200: {
2546 headers: {
2547 [name: string]: unknown;
2548 };
2549 content: {
2550 "application/json": components["schemas"]["TeamSummary"][];
2551 };
2552 };
2553 };
2554 };
2555 put?: never;
2556 /** Create a new team; admin is auto-added as the first admin member */
2557 post: {
2558 parameters: {
2559 query?: never;
2560 header?: never;
2561 path?: never;
2562 cookie?: never;
2563 };
2564 requestBody: {
2565 content: {
2566 "application/json": components["schemas"]["TeamCreate"];
2567 };
2568 };
2569 responses: {
2570 /** @description Created */
2571 201: {
2572 headers: {
2573 [name: string]: unknown;
2574 };
2575 content: {
2576 "application/json": components["schemas"]["Team"];
2577 };
2578 };
2579 /** @description A team with that slug already exists. */
2580 409: {
2581 headers: {
2582 [name: string]: unknown;
2583 };
2584 content: {
2585 "application/json": components["schemas"]["Error"];
2586 };
2587 };
2588 };
2589 };
2590 delete?: never;
2591 options?: never;
2592 head?: never;
2593 patch?: never;
2594 trace?: never;
2595 };
2596 "/api/v1/admin/teams/{team_id}": {
2597 parameters: {
2598 query?: never;
2599 header?: never;
2600 path: {
2601 team_id: string;
2602 };
2603 cookie?: never;
2604 };
2605 /** Fetch a team with its member roster (admin) */
2606 get: {
2607 parameters: {
2608 query?: never;
2609 header?: never;
2610 path: {
2611 team_id: string;
2612 };
2613 cookie?: never;
2614 };
2615 requestBody?: never;
2616 responses: {
2617 /** @description Team payload */
2618 200: {
2619 headers: {
2620 [name: string]: unknown;
2621 };
2622 content: {
2623 "application/json": components["schemas"]["Team"];
2624 };
2625 };
2626 };
2627 };
2628 put?: never;
2629 post?: never;
2630 /** Delete a team; CASCADES to team_members and team-scope user_skills */
2631 delete: {
2632 parameters: {
2633 query?: never;
2634 header?: never;
2635 path: {
2636 team_id: string;
2637 };
2638 cookie?: never;
2639 };
2640 requestBody?: never;
2641 responses: {
2642 /** @description Deleted */
2643 204: {
2644 headers: {
2645 [name: string]: unknown;
2646 };
2647 content?: never;
2648 };
2649 };
2650 };
2651 options?: never;
2652 head?: never;
2653 /** Update name / description (admin) */
2654 patch: {
2655 parameters: {
2656 query?: never;
2657 header?: never;
2658 path: {
2659 team_id: string;
2660 };
2661 cookie?: never;
2662 };
2663 requestBody: {
2664 content: {
2665 "application/json": components["schemas"]["TeamUpdate"];
2666 };
2667 };
2668 responses: {
2669 /** @description Updated team */
2670 200: {
2671 headers: {
2672 [name: string]: unknown;
2673 };
2674 content: {
2675 "application/json": components["schemas"]["Team"];
2676 };
2677 };
2678 };
2679 };
2680 trace?: never;
2681 };
2682 "/api/v1/admin/teams/{team_id}/members": {
2683 parameters: {
2684 query?: never;
2685 header?: never;
2686 path: {
2687 team_id: string;
2688 };
2689 cookie?: never;
2690 };
2691 get?: never;
2692 put?: never;
2693 /** Add a user to a team (admin) */
2694 post: {
2695 parameters: {
2696 query?: never;
2697 header?: never;
2698 path: {
2699 team_id: string;
2700 };
2701 cookie?: never;
2702 };
2703 requestBody: {
2704 content: {
2705 "application/json": {
2706 /** Format: uuid */
2707 user_id: string;
2708 /**
2709 * @default member
2710 * @enum {string}
2711 */
2712 role?: "admin" | "member";
2713 };
2714 };
2715 };
2716 responses: {
2717 /** @description Member added */
2718 201: {
2719 headers: {
2720 [name: string]: unknown;
2721 };
2722 content: {
2723 "application/json": components["schemas"]["TeamMember"];
2724 };
2725 };
2726 /** @description User is already a member of this team. */
2727 409: {
2728 headers: {
2729 [name: string]: unknown;
2730 };
2731 content: {
2732 "application/json": components["schemas"]["Error"];
2733 };
2734 };
2735 };
2736 };
2737 delete?: never;
2738 options?: never;
2739 head?: never;
2740 patch?: never;
2741 trace?: never;
2742 };
2743 "/api/v1/admin/teams/{team_id}/members/{user_id}": {
2744 parameters: {
2745 query?: never;
2746 header?: never;
2747 path: {
2748 team_id: string;
2749 user_id: string;
2750 };
2751 cookie?: never;
2752 };
2753 get?: never;
2754 put?: never;
2755 post?: never;
2756 /** Remove a user from a team (admin) */
2757 delete: {
2758 parameters: {
2759 query?: never;
2760 header?: never;
2761 path: {
2762 team_id: string;
2763 user_id: string;
2764 };
2765 cookie?: never;
2766 };
2767 requestBody?: never;
2768 responses: {
2769 /** @description Member removed */
2770 204: {
2771 headers: {
2772 [name: string]: unknown;
2773 };
2774 content?: never;
2775 };
2776 };
2777 };
2778 options?: never;
2779 head?: never;
2780 /** Change a member's role (admin) */
2781 patch: {
2782 parameters: {
2783 query?: never;
2784 header?: never;
2785 path: {
2786 team_id: string;
2787 user_id: string;
2788 };
2789 cookie?: never;
2790 };
2791 requestBody: {
2792 content: {
2793 "application/json": {
2794 /** @enum {string} */
2795 role: "admin" | "member";
2796 };
2797 };
2798 };
2799 responses: {
2800 /** @description Updated membership */
2801 200: {
2802 headers: {
2803 [name: string]: unknown;
2804 };
2805 content: {
2806 "application/json": components["schemas"]["TeamMember"];
2807 };
2808 };
2809 };
2810 };
2811 trace?: never;
2812 };
2813 "/api/v1/user-skills/{skill_id}": {
2814 parameters: {
2815 query?: never;
2816 header?: never;
2817 path: {
2818 skill_id: string;
2819 };
2820 cookie?: never;
2821 };
2822 /**
2823 * Fetch a single user- or team-scope skill (owner or team-admin)
2824 * @description Owner-only for ``scope='user'`` rows; team-admin-only for
2825 * ``scope='team'`` rows (D8.1b). Non-admin team members read team
2826 * skills through the merged picker at ``GET /api/v1/skills/{slug}``,
2827 * not through this management endpoint.
2828 */
2829 get: {
2830 parameters: {
2831 query?: never;
2832 header?: never;
2833 path: {
2834 skill_id: string;
2835 };
2836 cookie?: never;
2837 };
2838 requestBody?: never;
2839 responses: {
2840 /** @description Skill row */
2841 200: {
2842 headers: {
2843 [name: string]: unknown;
2844 };
2845 content: {
2846 "application/json": components["schemas"]["UserSkill"];
2847 };
2848 };
2849 /** @description Skill not found OR caller is not the owner / not a team-admin (id-probing-safe). */
2850 404: {
2851 headers: {
2852 [name: string]: unknown;
2853 };
2854 content: {
2855 "application/json": components["schemas"]["Error"];
2856 };
2857 };
2858 };
2859 };
2860 put?: never;
2861 post?: never;
2862 /**
2863 * Soft-delete (owner or team-admin)
2864 * @description Owner-only for ``scope='user'`` rows; team-admin-only for
2865 * ``scope='team'`` rows (D8.1b). Sets ``archived_at = now()``.
2866 * The slug is freed for a new skill at the same slug after
2867 * archive. Audit log records the deletion with the row's
2868 * identity; team-scope rows carry ``team_id`` in the details bag.
2869 */
2870 delete: {
2871 parameters: {
2872 query?: never;
2873 header?: never;
2874 path: {
2875 skill_id: string;
2876 };
2877 cookie?: never;
2878 };
2879 requestBody?: never;
2880 responses: {
2881 /** @description Deleted */
2882 204: {
2883 headers: {
2884 [name: string]: unknown;
2885 };
2886 content?: never;
2887 };
2888 /** @description Skill not found OR caller is not the owner / not a team-admin. */
2889 404: {
2890 headers: {
2891 [name: string]: unknown;
2892 };
2893 content: {
2894 "application/json": components["schemas"]["Error"];
2895 };
2896 };
2897 /** @description Skill is already archived. */
2898 410: {
2899 headers: {
2900 [name: string]: unknown;
2901 };
2902 content: {
2903 "application/json": components["schemas"]["Error"];
2904 };
2905 };
2906 };
2907 };
2908 options?: never;
2909 head?: never;
2910 /**
2911 * Partial update (owner or team-admin)
2912 * @description Owner-only for ``scope='user'`` rows; team-admin-only for
2913 * ``scope='team'`` rows (D8.1b). Audit details on team-scope
2914 * rows carry ``team_id`` alongside slug + changed fields.
2915 */
2916 patch: {
2917 parameters: {
2918 query?: never;
2919 header?: never;
2920 path: {
2921 skill_id: string;
2922 };
2923 cookie?: never;
2924 };
2925 requestBody: {
2926 content: {
2927 "application/json": components["schemas"]["UserSkillUpdate"];
2928 };
2929 };
2930 responses: {
2931 /** @description Updated row */
2932 200: {
2933 headers: {
2934 [name: string]: unknown;
2935 };
2936 content: {
2937 "application/json": components["schemas"]["UserSkill"];
2938 };
2939 };
2940 /** @description Skill not found OR caller is not the owner / not a team-admin. */
2941 404: {
2942 headers: {
2943 [name: string]: unknown;
2944 };
2945 content: {
2946 "application/json": components["schemas"]["Error"];
2947 };
2948 };
2949 };
2950 };
2951 trace?: never;
2952 };
2953 "/api/v1/user-skills/{skill_id}/versions": {
2954 parameters: {
2955 query?: never;
2956 header?: never;
2957 path: {
2958 skill_id: string;
2959 };
2960 cookie?: never;
2961 };
2962 /**
2963 * Audit-log view of edits for this user-skill (Wave D.2)
2964 * @description Returns ``audit_log`` rows for ``resource_type='user_skill'``
2965 * keyed by this skill id, ordered ``timestamp DESC`` (newest first).
2966 * The timeline UI renders top-down so the most recent edit appears
2967 * at the top; ``user_skill.created`` lands last.
2968 *
2969 * Access gate mirrors the mutable surface: owner-only for
2970 * ``scope='user'`` rows; team-admin-only for ``scope='team'`` rows.
2971 * 404 conflates "no such id" and "not your skill" (id-probing-safe).
2972 * Active AND archived rows are accessible so a freshly-archived
2973 * skill's timeline can still be rendered.
2974 */
2975 get: {
2976 parameters: {
2977 query?: {
2978 limit?: number;
2979 };
2980 header?: never;
2981 path: {
2982 skill_id: string;
2983 };
2984 cookie?: never;
2985 };
2986 requestBody?: never;
2987 responses: {
2988 /** @description Version history items, newest first */
2989 200: {
2990 headers: {
2991 [name: string]: unknown;
2992 };
2993 content: {
2994 "application/json": {
2995 items: {
2996 /** Format: date-time */
2997 timestamp: string;
2998 /** Format: uuid */
2999 actor_user_id?: string | null;
3000 actor_email?: string | null;
3001 /** @description e.g. 'user_skill.created' or 'user_skill.updated' */
3002 action: string;
3003 version?: string | null;
3004 details?: {
3005 [key: string]: unknown;
3006 } | null;
3007 }[];
3008 };
3009 };
3010 };
3011 /** @description Skill not found OR caller is not the owner / not a team-admin. */
3012 404: {
3013 headers: {
3014 [name: string]: unknown;
3015 };
3016 content: {
3017 "application/json": components["schemas"]["Error"];
3018 };
3019 };
3020 };
3021 };
3022 put?: never;
3023 post?: never;
3024 delete?: never;
3025 options?: never;
3026 head?: never;
3027 patch?: never;
3028 trace?: never;
3029 };
3030 "/api/v1/models": {
3031 parameters: {
3032 query?: never;
3033 header?: never;
3034 path?: never;
3035 cookie?: never;
3036 };
3037 /**
3038 * List available models — proxy to gateway /v1/models (D0)
3039 * @description Authenticated proxy that forwards the gateway's merged
3040 * ``GET /v1/models`` payload (aliases + live-discovered Ollama
3041 * tags + live-discovered Anthropic catalog rows). The LQ.AI shell's
3042 * model picker consumes this endpoint; the response shape is
3043 * identical to the gateway's per
3044 * ``docs/api/gateway-openapi.yaml`` so the contract stays single-
3045 * sourced.
3046 *
3047 * Auth: bearer token + cleared ``must_change_password``. The
3048 * picker contents reveal which providers the operator has
3049 * configured, so anonymous reads are intentionally not allowed.
3050 *
3051 * Errors:
3052 * - Gateway timeout → 504 ``gateway_timeout``.
3053 * - Gateway unreachable / 5xx / 401 → 503 ``gateway_unreachable``.
3054 * A 401 from the gateway is operator-side misconfiguration; the
3055 * user must not see the underlying detail.
3056 */
3057 get: {
3058 parameters: {
3059 query?: never;
3060 header?: never;
3061 path?: never;
3062 cookie?: never;
3063 };
3064 requestBody?: never;
3065 responses: {
3066 /** @description Model list */
3067 200: {
3068 headers: {
3069 [name: string]: unknown;
3070 };
3071 content: {
3072 "application/json": {
3073 /** @enum {string} */
3074 object: "list";
3075 data: {
3076 id: string;
3077 /** @enum {string} */
3078 object: "model";
3079 created: number;
3080 owned_by: string;
3081 /** @enum {string} */
3082 lq_ai_kind: "alias" | "provider_native";
3083 /** @enum {integer} */
3084 routed_inference_tier?: 1 | 2 | 3 | 4 | 5;
3085 /** @enum {string} */
3086 provider_type?: "anthropic" | "openai" | "vertex" | "cohere" | "azure_openai" | "bedrock" | "ollama" | "vllm" | "openai_compatible";
3087 lq_ai_resolves_to?: string;
3088 lq_ai_fallback_count?: number;
3089 }[];
3090 };
3091 };
3092 };
3093 /** @description Missing or invalid bearer token */
3094 401: {
3095 headers: {
3096 [name: string]: unknown;
3097 };
3098 content: {
3099 "application/json": components["schemas"]["Error"];
3100 };
3101 };
3102 /** @description Gateway unreachable */
3103 503: {
3104 headers: {
3105 [name: string]: unknown;
3106 };
3107 content: {
3108 "application/json": components["schemas"]["Error"];
3109 };
3110 };
3111 /** @description Gateway timed out */
3112 504: {
3113 headers: {
3114 [name: string]: unknown;
3115 };
3116 content: {
3117 "application/json": components["schemas"]["Error"];
3118 };
3119 };
3120 };
3121 };
3122 put?: never;
3123 post?: never;
3124 delete?: never;
3125 options?: never;
3126 head?: never;
3127 patch?: never;
3128 trace?: never;
3129 };
3130 "/api/v1/internal/skills/{skill_name}": {
3131 parameters: {
3132 query?: {
3133 /**
3134 * @description When supplied, the resolver applies the D8.1b stack (per
3135 * ADR 0012): user shadow → team shadow → filesystem built-in.
3136 * A non-archived ``user_skills`` row for that user at this slug
3137 * wins outright; otherwise the newest non-archived team-scope
3138 * row owned by any team the user is a member of wins;
3139 * otherwise the filesystem-canonical built-in is returned.
3140 * When omitted, the registry view (built-in only) is returned.
3141 */
3142 user_id?: string;
3143 };
3144 header?: never;
3145 path: {
3146 skill_name: string;
3147 };
3148 cookie?: never;
3149 };
3150 /**
3151 * Internal — fetch a skill (gateway → backend; user > team > built-in)
3152 * @description Service-to-service endpoint used by the Inference Gateway during
3153 * prompt assembly (Task C2 / ADR 0007). The user-facing
3154 * `GET /api/v1/skills/{name}` endpoint is gated by user-token auth
3155 * (`get_active_user`) and is inappropriate for the gateway's calls
3156 * — the gateway has no user. This route is gated by the shared
3157 * `X-LQ-AI-Gateway-Key` secret instead.
3158 *
3159 * Trust-domain separation: user-facing routes stay under user-token
3160 * auth; internal routes stay under shared-secret auth. The two
3161 * never mix on a single route.
3162 *
3163 * The optional ``user_id`` query param activates the D8.1b
3164 * resolution stack (user > team > built-in). Multi-team conflicts
3165 * resolve to the row with the most recent ``updated_at``. The
3166 * gateway's skill cache stays keyed on ``(name, user_id)``;
3167 * team-membership changes propagate via the existing TTL.
3168 *
3169 * The response shape matches `GET /api/v1/skills/{name}` (the
3170 * `Skill` schema) so the gateway-side client reuses the same
3171 * response model.
3172 */
3173 get: {
3174 parameters: {
3175 query?: {
3176 /**
3177 * @description When supplied, the resolver applies the D8.1b stack (per
3178 * ADR 0012): user shadow → team shadow → filesystem built-in.
3179 * A non-archived ``user_skills`` row for that user at this slug
3180 * wins outright; otherwise the newest non-archived team-scope
3181 * row owned by any team the user is a member of wins;
3182 * otherwise the filesystem-canonical built-in is returned.
3183 * When omitted, the registry view (built-in only) is returned.
3184 */
3185 user_id?: string;
3186 };
3187 header?: never;
3188 path: {
3189 skill_name: string;
3190 };
3191 cookie?: never;
3192 };
3193 requestBody?: never;
3194 responses: {
3195 /** @description Skill detail */
3196 200: {
3197 headers: {
3198 [name: string]: unknown;
3199 };
3200 content: {
3201 "application/json": components["schemas"]["Skill"];
3202 };
3203 };
3204 /** @description Missing or invalid `X-LQ-AI-Gateway-Key`. */
3205 401: {
3206 headers: {
3207 [name: string]: unknown;
3208 };
3209 content: {
3210 "application/json": components["schemas"]["Error"];
3211 };
3212 };
3213 /** @description No skill with that name is in the registry. */
3214 404: {
3215 headers: {
3216 [name: string]: unknown;
3217 };
3218 content: {
3219 "application/json": components["schemas"]["Error"];
3220 };
3221 };
3222 /**
3223 * @description Operator has not configured `LQ_AI_GATEWAY_KEY` on the
3224 * backend; service-to-service traffic is refused rather than
3225 * silently accepted.
3226 */
3227 500: {
3228 headers: {
3229 [name: string]: unknown;
3230 };
3231 content: {
3232 "application/json": components["schemas"]["Error"];
3233 };
3234 };
3235 };
3236 };
3237 put?: never;
3238 post?: never;
3239 delete?: never;
3240 options?: never;
3241 head?: never;
3242 patch?: never;
3243 trace?: never;
3244 };
3245 "/api/v1/internal/organization-profile": {
3246 parameters: {
3247 query?: never;
3248 header?: never;
3249 path?: never;
3250 cookie?: never;
3251 };
3252 /**
3253 * Internal — fetch the deployment's Organization Profile (gateway → backend)
3254 * @description Service-to-service endpoint used by the Inference Gateway during
3255 * prompt assembly (Task D4-coverage). Returns the Organization
3256 * Profile (PRD §3.12) as a `Skill`-shaped JSON body so the
3257 * gateway can plug it into the same prompt-assembler that
3258 * consumes user-attached skills. The synthesized frontmatter
3259 * carries `is_organization_profile: true` and
3260 * `use_organization_profile: false` so consumers identify the
3261 * Profile by metadata and the assembler never recursively
3262 * re-prepends the Profile to itself.
3263 *
3264 * Same trust posture as `/internal/skills/{name}`:
3265 * `X-LQ-AI-Gateway-Key` shared-secret auth (constant-time
3266 * compare); user-facing reads of the Profile use the bearer-
3267 * authed `/api/v1/organization-profile` route instead.
3268 */
3269 get: {
3270 parameters: {
3271 query?: never;
3272 header?: never;
3273 path?: never;
3274 cookie?: never;
3275 };
3276 requestBody?: never;
3277 responses: {
3278 /** @description Profile present; body is the `Skill`-shaped synthesized payload. */
3279 200: {
3280 headers: {
3281 [name: string]: unknown;
3282 };
3283 content: {
3284 "application/json": components["schemas"]["Skill"];
3285 };
3286 };
3287 /** @description Missing or invalid `X-LQ-AI-Gateway-Key`. */
3288 401: {
3289 headers: {
3290 [name: string]: unknown;
3291 };
3292 content: {
3293 "application/json": components["schemas"]["Error"];
3294 };
3295 };
3296 /**
3297 * @description No Profile is set on this deployment, or the Profile's body
3298 * is empty. The gateway treats this as "no Profile to
3299 * prepend" and proceeds with skill-only prompt assembly.
3300 */
3301 404: {
3302 headers: {
3303 [name: string]: unknown;
3304 };
3305 content: {
3306 "application/json": components["schemas"]["Error"];
3307 };
3308 };
3309 /**
3310 * @description Operator has not configured `LQ_AI_GATEWAY_KEY` on the
3311 * backend; service-to-service traffic is refused rather than
3312 * silently accepted.
3313 */
3314 500: {
3315 headers: {
3316 [name: string]: unknown;
3317 };
3318 content: {
3319 "application/json": components["schemas"]["Error"];
3320 };
3321 };
3322 };
3323 };
3324 put?: never;
3325 post?: never;
3326 delete?: never;
3327 options?: never;
3328 head?: never;
3329 patch?: never;
3330 trace?: never;
3331 };
3332 "/api/v1/files": {
3333 parameters: {
3334 query?: never;
3335 header?: never;
3336 path?: never;
3337 cookie?: never;
3338 };
3339 get?: never;
3340 put?: never;
3341 /**
3342 * Upload a file
3343 * @description Streaming multipart upload. The body is streamed to MinIO without
3344 * loading the whole file into memory; a SHA-256 is computed as bytes
3345 * flow past, and metadata is persisted with `ingestion_status='pending'`.
3346 * The document pipeline (Task C5) picks the row up asynchronously
3347 * and flips status through `processing` → `ready` (or `failed`).
3348 *
3349 * Per-request size limit: `LQ_AI_MAX_UPLOAD_SIZE_MB` (default 100 MB
3350 * per Task C4). Exceeding it returns 413 with `code=payload_too_large`.
3351 *
3352 * `project_id` is accepted for forward compatibility (it appears in
3353 * the multipart body) but is currently ignored; project attachment
3354 * lands in C7. Files always start unattached and are linked to a
3355 * project via `POST /api/v1/projects/{project_id}/files` (C7).
3356 */
3357 post: {
3358 parameters: {
3359 query?: never;
3360 header?: never;
3361 path?: never;
3362 cookie?: never;
3363 };
3364 requestBody: {
3365 content: {
3366 "multipart/form-data": {
3367 /** Format: binary */
3368 file: string;
3369 /** Format: uuid */
3370 project_id?: string | null;
3371 };
3372 };
3373 };
3374 responses: {
3375 /** @description File uploaded; ingestion may be async. */
3376 201: {
3377 headers: {
3378 [name: string]: unknown;
3379 };
3380 content: {
3381 "application/json": components["schemas"]["File"];
3382 };
3383 };
3384 /** @description Validation error (e.g., missing filename on multipart part). */
3385 400: {
3386 headers: {
3387 [name: string]: unknown;
3388 };
3389 content: {
3390 "application/json": components["schemas"]["Error"];
3391 };
3392 };
3393 /** @description Missing or invalid bearer token. */
3394 401: {
3395 headers: {
3396 [name: string]: unknown;
3397 };
3398 content: {
3399 "application/json": components["schemas"]["Error"];
3400 };
3401 };
3402 /** @description User must change their password before uploading (B2 gate). */
3403 403: {
3404 headers: {
3405 [name: string]: unknown;
3406 };
3407 content: {
3408 "application/json": components["schemas"]["Error"];
3409 };
3410 };
3411 /**
3412 * @description Uploaded body exceeds the per-request size cap
3413 * (`LQ_AI_MAX_UPLOAD_SIZE_MB`, default 100 MB). The response
3414 * body's `details` carries `limit_bytes` and `received_bytes`.
3415 */
3416 413: {
3417 headers: {
3418 [name: string]: unknown;
3419 };
3420 content: {
3421 "application/json": components["schemas"]["Error"];
3422 };
3423 };
3424 };
3425 };
3426 delete?: never;
3427 options?: never;
3428 head?: never;
3429 patch?: never;
3430 trace?: never;
3431 };
3432 "/api/v1/files/{file_id}": {
3433 parameters: {
3434 query?: never;
3435 header?: never;
3436 path: {
3437 file_id: string;
3438 };
3439 cookie?: never;
3440 };
3441 /** Get file metadata */
3442 get: {
3443 parameters: {
3444 query?: never;
3445 header?: never;
3446 path: {
3447 file_id: string;
3448 };
3449 cookie?: never;
3450 };
3451 requestBody?: never;
3452 responses: {
3453 /** @description File metadata. */
3454 200: {
3455 headers: {
3456 [name: string]: unknown;
3457 };
3458 content: {
3459 "application/json": components["schemas"]["File"];
3460 };
3461 };
3462 /** @description `file_id` is not a valid UUID. */
3463 400: {
3464 headers: {
3465 [name: string]: unknown;
3466 };
3467 content: {
3468 "application/json": components["schemas"]["Error"];
3469 };
3470 };
3471 /** @description Missing or invalid bearer token. */
3472 401: {
3473 headers: {
3474 [name: string]: unknown;
3475 };
3476 content: {
3477 "application/json": components["schemas"]["Error"];
3478 };
3479 };
3480 /**
3481 * @description File does not exist, has been soft-deleted, or is owned by a
3482 * different user. The cross-user case returns 404 (not 403) to
3483 * avoid leaking existence information.
3484 */
3485 404: {
3486 headers: {
3487 [name: string]: unknown;
3488 };
3489 content: {
3490 "application/json": components["schemas"]["Error"];
3491 };
3492 };
3493 };
3494 };
3495 put?: never;
3496 post?: never;
3497 /**
3498 * Soft-delete a file
3499 * @description Sets `deleted_at` on the row; the MinIO object is left in place
3500 * and reaped later by D6 (per-user export+delete) or a future GC
3501 * sweep, per `docs/adr/0005-file-storage-soft-delete-and-key-scheme.md`.
3502 * Idempotent: deleting an already-soft-deleted or missing file
3503 * returns 404.
3504 */
3505 delete: {
3506 parameters: {
3507 query?: never;
3508 header?: never;
3509 path: {
3510 file_id: string;
3511 };
3512 cookie?: never;
3513 };
3514 requestBody?: never;
3515 responses: {
3516 /** @description File soft-deleted (no body). */
3517 204: {
3518 headers: {
3519 [name: string]: unknown;
3520 };
3521 content?: never;
3522 };
3523 /** @description `file_id` is not a valid UUID. */
3524 400: {
3525 headers: {
3526 [name: string]: unknown;
3527 };
3528 content: {
3529 "application/json": components["schemas"]["Error"];
3530 };
3531 };
3532 /** @description Missing or invalid bearer token. */
3533 401: {
3534 headers: {
3535 [name: string]: unknown;
3536 };
3537 content: {
3538 "application/json": components["schemas"]["Error"];
3539 };
3540 };
3541 /** @description File missing, soft-deleted, or owned by a different user. */
3542 404: {
3543 headers: {
3544 [name: string]: unknown;
3545 };
3546 content: {
3547 "application/json": components["schemas"]["Error"];
3548 };
3549 };
3550 };
3551 };
3552 options?: never;
3553 head?: never;
3554 patch?: never;
3555 trace?: never;
3556 };
3557 "/api/v1/files/{file_id}/content": {
3558 parameters: {
3559 query?: never;
3560 header?: never;
3561 path: {
3562 file_id: string;
3563 };
3564 cookie?: never;
3565 };
3566 /**
3567 * Download original file content
3568 * @description Streams the original bytes back as the upload arrived. The
3569 * `Content-Type` is the stored MIME type, `Content-Length` is the
3570 * stored size in bytes, and `Content-Disposition` is
3571 * `attachment; filename="..."` with an RFC 5987 `filename*=UTF-8''...`
3572 * for non-ASCII filenames.
3573 */
3574 get: {
3575 parameters: {
3576 query?: never;
3577 header?: never;
3578 path: {
3579 file_id: string;
3580 };
3581 cookie?: never;
3582 };
3583 requestBody?: never;
3584 responses: {
3585 /** @description File bytes (streaming). */
3586 200: {
3587 headers: {
3588 /**
3589 * @description `attachment; filename="..."` (RFC 6266); for non-ASCII
3590 * filenames an additional RFC 5987 `filename*=UTF-8''...`
3591 * parameter is included.
3592 */
3593 "Content-Disposition"?: string;
3594 /** @description Always `nosniff`. */
3595 "X-Content-Type-Options"?: string;
3596 [name: string]: unknown;
3597 };
3598 content: {
3599 "application/octet-stream": unknown;
3600 };
3601 };
3602 /** @description `file_id` is not a valid UUID. */
3603 400: {
3604 headers: {
3605 [name: string]: unknown;
3606 };
3607 content: {
3608 "application/json": components["schemas"]["Error"];
3609 };
3610 };
3611 /** @description Missing or invalid bearer token. */
3612 401: {
3613 headers: {
3614 [name: string]: unknown;
3615 };
3616 content: {
3617 "application/json": components["schemas"]["Error"];
3618 };
3619 };
3620 /** @description File missing, soft-deleted, or owned by a different user. */
3621 404: {
3622 headers: {
3623 [name: string]: unknown;
3624 };
3625 content: {
3626 "application/json": components["schemas"]["Error"];
3627 };
3628 };
3629 };
3630 };
3631 put?: never;
3632 post?: never;
3633 delete?: never;
3634 options?: never;
3635 head?: never;
3636 patch?: never;
3637 trace?: never;
3638 };
3639 "/api/v1/knowledge-bases": {
3640 parameters: {
3641 query?: never;
3642 header?: never;
3643 path?: never;
3644 cookie?: never;
3645 };
3646 /** List the caller's knowledge bases */
3647 get: {
3648 parameters: {
3649 query?: {
3650 /** @description When true, list archived KBs. Default (omit) lists active only. */
3651 archived?: boolean;
3652 /** @description Filter to KBs associated with this project. */
3653 project_id?: string;
3654 };
3655 header?: never;
3656 path?: never;
3657 cookie?: never;
3658 };
3659 requestBody?: never;
3660 responses: {
3661 /** @description KBs accessible to the user */
3662 200: {
3663 headers: {
3664 [name: string]: unknown;
3665 };
3666 content: {
3667 "application/json": components["schemas"]["KnowledgeBase"][];
3668 };
3669 };
3670 };
3671 };
3672 put?: never;
3673 /** Create a knowledge base */
3674 post: {
3675 parameters: {
3676 query?: never;
3677 header?: never;
3678 path?: never;
3679 cookie?: never;
3680 };
3681 requestBody: {
3682 content: {
3683 "application/json": components["schemas"]["KnowledgeBaseCreate"];
3684 };
3685 };
3686 responses: {
3687 /** @description KB created */
3688 201: {
3689 headers: {
3690 [name: string]: unknown;
3691 };
3692 content: {
3693 "application/json": components["schemas"]["KnowledgeBase"];
3694 };
3695 };
3696 /** @description Project (if `project_id` was provided) not found. */
3697 404: {
3698 headers: {
3699 [name: string]: unknown;
3700 };
3701 content: {
3702 "application/json": components["schemas"]["Error"];
3703 };
3704 };
3705 };
3706 };
3707 delete?: never;
3708 options?: never;
3709 head?: never;
3710 patch?: never;
3711 trace?: never;
3712 };
3713 "/api/v1/knowledge-bases/{kb_id}": {
3714 parameters: {
3715 query?: never;
3716 header?: never;
3717 path: {
3718 kb_id: string;
3719 };
3720 cookie?: never;
3721 };
3722 /** Fetch a single knowledge base with metadata + file count */
3723 get: {
3724 parameters: {
3725 query?: never;
3726 header?: never;
3727 path: {
3728 kb_id: string;
3729 };
3730 cookie?: never;
3731 };
3732 requestBody?: never;
3733 responses: {
3734 /** @description Knowledge base */
3735 200: {
3736 headers: {
3737 [name: string]: unknown;
3738 };
3739 content: {
3740 "application/json": components["schemas"]["KnowledgeBase"];
3741 };
3742 };
3743 /** @description Not found */
3744 404: {
3745 headers: {
3746 [name: string]: unknown;
3747 };
3748 content: {
3749 "application/json": components["schemas"]["Error"];
3750 };
3751 };
3752 };
3753 };
3754 put?: never;
3755 post?: never;
3756 /** Soft-delete a knowledge base */
3757 delete: {
3758 parameters: {
3759 query?: never;
3760 header?: never;
3761 path: {
3762 kb_id: string;
3763 };
3764 cookie?: never;
3765 };
3766 requestBody?: never;
3767 responses: {
3768 /** @description Soft-deleted */
3769 204: {
3770 headers: {
3771 [name: string]: unknown;
3772 };
3773 content?: never;
3774 };
3775 /** @description Not found */
3776 404: {
3777 headers: {
3778 [name: string]: unknown;
3779 };
3780 content: {
3781 "application/json": components["schemas"]["Error"];
3782 };
3783 };
3784 };
3785 };
3786 options?: never;
3787 head?: never;
3788 /** Partial update — name, description, project association, alpha, or archived */
3789 patch: {
3790 parameters: {
3791 query?: never;
3792 header?: never;
3793 path: {
3794 kb_id: string;
3795 };
3796 cookie?: never;
3797 };
3798 requestBody: {
3799 content: {
3800 "application/json": components["schemas"]["KnowledgeBaseUpdate"];
3801 };
3802 };
3803 responses: {
3804 /** @description Updated */
3805 200: {
3806 headers: {
3807 [name: string]: unknown;
3808 };
3809 content: {
3810 "application/json": components["schemas"]["KnowledgeBase"];
3811 };
3812 };
3813 /** @description Not found */
3814 404: {
3815 headers: {
3816 [name: string]: unknown;
3817 };
3818 content: {
3819 "application/json": components["schemas"]["Error"];
3820 };
3821 };
3822 };
3823 };
3824 trace?: never;
3825 };
3826 "/api/v1/knowledge-bases/{kb_id}/files": {
3827 parameters: {
3828 query?: never;
3829 header?: never;
3830 path: {
3831 kb_id: string;
3832 };
3833 cookie?: never;
3834 };
3835 /**
3836 * List the files attached to a knowledge base
3837 * @description Returns the files currently attached to the KB (the `File`
3838 * shape from `GET /files/{id}` plus the `attached_at` timestamp
3839 * from the join). Owner-scoped — cross-user / unknown KB id
3840 * returns 404. Soft-deleted files are excluded. Sorted by
3841 * `attached_at DESC` so the most recent uploads surface first.
3842 *
3843 * Drives the Knowledge surface's detail-page document list per
3844 * the M1 frontend design spec (Wave C).
3845 */
3846 get: {
3847 parameters: {
3848 query?: never;
3849 header?: never;
3850 path: {
3851 kb_id: string;
3852 };
3853 cookie?: never;
3854 };
3855 requestBody?: never;
3856 responses: {
3857 /** @description List of attached files */
3858 200: {
3859 headers: {
3860 [name: string]: unknown;
3861 };
3862 content: {
3863 "application/json": components["schemas"]["KBFile"][];
3864 };
3865 };
3866 /** @description KB not found / cross-user */
3867 404: {
3868 headers: {
3869 [name: string]: unknown;
3870 };
3871 content: {
3872 "application/json": components["schemas"]["Error"];
3873 };
3874 };
3875 };
3876 };
3877 put?: never;
3878 /**
3879 * Attach a file to a knowledge base
3880 * @description The file must be owned by the caller and have completed the C5
3881 * ingest pipeline (`ingestion_status='ready'`). After successful
3882 * attach the backend enqueues an embed job; the query path also
3883 * covers any unembedded chunks lazily (embed-on-read).
3884 */
3885 post: {
3886 parameters: {
3887 query?: never;
3888 header?: never;
3889 path: {
3890 kb_id: string;
3891 };
3892 cookie?: never;
3893 };
3894 requestBody: {
3895 content: {
3896 "application/json": {
3897 /** Format: uuid */
3898 file_id: string;
3899 };
3900 };
3901 };
3902 responses: {
3903 /** @description Attached */
3904 204: {
3905 headers: {
3906 [name: string]: unknown;
3907 };
3908 content?: never;
3909 };
3910 /** @description file_id is malformed */
3911 400: {
3912 headers: {
3913 [name: string]: unknown;
3914 };
3915 content: {
3916 "application/json": components["schemas"]["Error"];
3917 };
3918 };
3919 /** @description KB or file not found / cross-user */
3920 404: {
3921 headers: {
3922 [name: string]: unknown;
3923 };
3924 content: {
3925 "application/json": components["schemas"]["Error"];
3926 };
3927 };
3928 /** @description File already attached to this KB (idempotency-violating POST) */
3929 409: {
3930 headers: {
3931 [name: string]: unknown;
3932 };
3933 content: {
3934 "application/json": components["schemas"]["Error"];
3935 };
3936 };
3937 /** @description File is not in `ingestion_status='ready'` */
3938 422: {
3939 headers: {
3940 [name: string]: unknown;
3941 };
3942 content: {
3943 "application/json": components["schemas"]["Error"];
3944 };
3945 };
3946 };
3947 };
3948 delete?: never;
3949 options?: never;
3950 head?: never;
3951 patch?: never;
3952 trace?: never;
3953 };
3954 "/api/v1/knowledge-bases/{kb_id}/files/{file_id}": {
3955 parameters: {
3956 query?: never;
3957 header?: never;
3958 path: {
3959 kb_id: string;
3960 file_id: string;
3961 };
3962 cookie?: never;
3963 };
3964 get?: never;
3965 put?: never;
3966 post?: never;
3967 /** Detach a file from a knowledge base */
3968 delete: {
3969 parameters: {
3970 query?: never;
3971 header?: never;
3972 path: {
3973 kb_id: string;
3974 file_id: string;
3975 };
3976 cookie?: never;
3977 };
3978 requestBody?: never;
3979 responses: {
3980 /** @description Detached */
3981 204: {
3982 headers: {
3983 [name: string]: unknown;
3984 };
3985 content?: never;
3986 };
3987 /** @description KB not found, or the file is not attached */
3988 404: {
3989 headers: {
3990 [name: string]: unknown;
3991 };
3992 content: {
3993 "application/json": components["schemas"]["Error"];
3994 };
3995 };
3996 };
3997 };
3998 options?: never;
3999 head?: never;
4000 patch?: never;
4001 trace?: never;
4002 };
4003 "/api/v1/knowledge-bases/{kb_id}/query": {
4004 parameters: {
4005 query?: never;
4006 header?: never;
4007 path: {
4008 kb_id: string;
4009 };
4010 cookie?: never;
4011 };
4012 get?: never;
4013 put?: never;
4014 /**
4015 * Hybrid (vector + FTS) search over the knowledge base
4016 * @description Per ADR 0008 the score is `(1 - alpha) * vector + alpha * fts`,
4017 * where each side is min-max normalized across the union of the
4018 * per-side candidate sets (each side returns up to `top_k * 4`
4019 * candidates). `hybrid_alpha` defaults to the KB's stored value
4020 * (which itself defaults to 0.5).
4021 *
4022 * Embed-on-read: if the gateway's `/v1/embeddings` is unavailable
4023 * the query degrades gracefully to FTS-only ranking; the response
4024 * carries `score_components.vector = 0` for every result in that
4025 * case so the client can detect the degraded mode.
4026 */
4027 post: {
4028 parameters: {
4029 query?: never;
4030 header?: never;
4031 path: {
4032 kb_id: string;
4033 };
4034 cookie?: never;
4035 };
4036 requestBody: {
4037 content: {
4038 "application/json": components["schemas"]["KBQueryRequest"];
4039 };
4040 };
4041 responses: {
4042 /** @description Search results */
4043 200: {
4044 headers: {
4045 [name: string]: unknown;
4046 };
4047 content: {
4048 "application/json": components["schemas"]["KBQueryResponse"];
4049 };
4050 };
4051 /** @description KB not found / cross-user */
4052 404: {
4053 headers: {
4054 [name: string]: unknown;
4055 };
4056 content: {
4057 "application/json": components["schemas"]["Error"];
4058 };
4059 };
4060 };
4061 };
4062 delete?: never;
4063 options?: never;
4064 head?: never;
4065 patch?: never;
4066 trace?: never;
4067 };
4068 "/api/v1/organization-profile": {
4069 parameters: {
4070 query?: never;
4071 header?: never;
4072 path?: never;
4073 cookie?: never;
4074 };
4075 /**
4076 * Get the deployment's Organization Profile (singleton)
4077 * @description Bearer-authenticated. Readable by every authenticated user
4078 * (PRD §1.3 transparency: users are entitled to see what's
4079 * shaping their output). Returns `content_md=""` plus null
4080 * timestamps when no admin has set a Profile yet — the read
4081 * path never 404s.
4082 */
4083 get: {
4084 parameters: {
4085 query?: never;
4086 header?: never;
4087 path?: never;
4088 cookie?: never;
4089 };
4090 requestBody?: never;
4091 responses: {
4092 /** @description Organization Profile (or empty placeholder) */
4093 200: {
4094 headers: {
4095 [name: string]: unknown;
4096 };
4097 content: {
4098 "application/json": {
4099 content_md: string;
4100 /** Format: date-time */
4101 updated_at?: string | null;
4102 /** Format: uuid */
4103 updated_by?: string | null;
4104 };
4105 };
4106 };
4107 };
4108 };
4109 /**
4110 * Update the Organization Profile (admin only)
4111 * @description Admin-only upsert: idempotent against the singleton row. Empty
4112 * `content_md` is allowed (operators may want to clear without
4113 * deleting). Audit-logged as `organization_profile.updated`.
4114 */
4115 put: {
4116 parameters: {
4117 query?: never;
4118 header?: never;
4119 path?: never;
4120 cookie?: never;
4121 };
4122 requestBody: {
4123 content: {
4124 "application/json": {
4125 content_md: string;
4126 };
4127 };
4128 };
4129 responses: {
4130 /** @description Updated */
4131 200: {
4132 headers: {
4133 [name: string]: unknown;
4134 };
4135 content: {
4136 "application/json": {
4137 content_md: string;
4138 /** Format: date-time */
4139 updated_at?: string | null;
4140 /** Format: uuid */
4141 updated_by?: string | null;
4142 };
4143 };
4144 };
4145 /** @description Bearer token missing or invalid */
4146 401: {
4147 headers: {
4148 [name: string]: unknown;
4149 };
4150 content?: never;
4151 };
4152 /** @description Caller is not an admin */
4153 403: {
4154 headers: {
4155 [name: string]: unknown;
4156 };
4157 content?: never;
4158 };
4159 };
4160 };
4161 post?: never;
4162 delete?: never;
4163 options?: never;
4164 head?: never;
4165 patch?: never;
4166 trace?: never;
4167 };
4168 "/api/v1/organization-profile/raw": {
4169 parameters: {
4170 query?: never;
4171 header?: never;
4172 path?: never;
4173 cookie?: never;
4174 };
4175 /**
4176 * Get the Profile body as raw Markdown
4177 * @description Bearer-authenticated. Convenience endpoint for the Skill
4178 * Inspector (§3.4) and any UI surface that wants to render the
4179 * Profile as Markdown without JSON-decoding the body. Returns
4180 * an empty 200 when no Profile is set.
4181 */
4182 get: {
4183 parameters: {
4184 query?: never;
4185 header?: never;
4186 path?: never;
4187 cookie?: never;
4188 };
4189 requestBody?: never;
4190 responses: {
4191 /** @description Profile body */
4192 200: {
4193 headers: {
4194 [name: string]: unknown;
4195 };
4196 content: {
4197 "text/markdown": unknown;
4198 };
4199 };
4200 };
4201 };
4202 put?: never;
4203 post?: never;
4204 delete?: never;
4205 options?: never;
4206 head?: never;
4207 patch?: never;
4208 trace?: never;
4209 };
4210 "/api/v1/saved-prompts": {
4211 parameters: {
4212 query?: never;
4213 header?: never;
4214 path?: never;
4215 cookie?: never;
4216 };
4217 get: {
4218 parameters: {
4219 query?: never;
4220 header?: never;
4221 path?: never;
4222 cookie?: never;
4223 };
4224 requestBody?: never;
4225 responses: {
4226 /** @description User's saved prompts */
4227 200: {
4228 headers: {
4229 [name: string]: unknown;
4230 };
4231 content: {
4232 "application/json": components["schemas"]["SavedPrompt"][];
4233 };
4234 };
4235 };
4236 };
4237 put?: never;
4238 post: {
4239 parameters: {
4240 query?: never;
4241 header?: never;
4242 path?: never;
4243 cookie?: never;
4244 };
4245 requestBody: {
4246 content: {
4247 "application/json": {
4248 name: string;
4249 prompt_text: string;
4250 tags?: string[];
4251 };
4252 };
4253 };
4254 responses: {
4255 /** @description Created */
4256 201: {
4257 headers: {
4258 [name: string]: unknown;
4259 };
4260 content: {
4261 "application/json": components["schemas"]["SavedPrompt"];
4262 };
4263 };
4264 };
4265 };
4266 delete?: never;
4267 options?: never;
4268 head?: never;
4269 patch?: never;
4270 trace?: never;
4271 };
4272 "/api/v1/saved-prompts/{prompt_id}": {
4273 parameters: {
4274 query?: never;
4275 header?: never;
4276 path: {
4277 prompt_id: string;
4278 };
4279 cookie?: never;
4280 };
4281 /** Fetch a single saved prompt */
4282 get: {
4283 parameters: {
4284 query?: never;
4285 header?: never;
4286 path: {
4287 prompt_id: string;
4288 };
4289 cookie?: never;
4290 };
4291 requestBody?: never;
4292 responses: {
4293 /** @description Saved prompt */
4294 200: {
4295 headers: {
4296 [name: string]: unknown;
4297 };
4298 content: {
4299 "application/json": components["schemas"]["SavedPrompt"];
4300 };
4301 };
4302 /** @description Not found */
4303 404: {
4304 headers: {
4305 [name: string]: unknown;
4306 };
4307 content?: never;
4308 };
4309 };
4310 };
4311 put?: never;
4312 post?: never;
4313 delete: {
4314 parameters: {
4315 query?: never;
4316 header?: never;
4317 path: {
4318 prompt_id: string;
4319 };
4320 cookie?: never;
4321 };
4322 requestBody?: never;
4323 responses: {
4324 /** @description Deleted */
4325 204: {
4326 headers: {
4327 [name: string]: unknown;
4328 };
4329 content?: never;
4330 };
4331 };
4332 };
4333 options?: never;
4334 head?: never;
4335 patch: {
4336 parameters: {
4337 query?: never;
4338 header?: never;
4339 path: {
4340 prompt_id: string;
4341 };
4342 cookie?: never;
4343 };
4344 requestBody: {
4345 content: {
4346 "application/json": {
4347 name?: string;
4348 prompt_text?: string;
4349 tags?: string[];
4350 };
4351 };
4352 };
4353 responses: {
4354 /** @description Updated */
4355 200: {
4356 headers: {
4357 [name: string]: unknown;
4358 };
4359 content: {
4360 "application/json": components["schemas"]["SavedPrompt"];
4361 };
4362 };
4363 };
4364 };
4365 trace?: never;
4366 };
4367 "/api/v1/admin/audit-log": {
4368 parameters: {
4369 query?: never;
4370 header?: never;
4371 path?: never;
4372 cookie?: never;
4373 };
4374 /** Query audit log (admin only) */
4375 get: {
4376 parameters: {
4377 query?: {
4378 user_id?: string;
4379 action?: string;
4380 resource_type?: string;
4381 privilege_marked?: boolean;
4382 routed_inference_tier?: 1 | 2 | 3 | 4 | 5;
4383 from?: string;
4384 to?: string;
4385 cursor?: string;
4386 };
4387 header?: never;
4388 path?: never;
4389 cookie?: never;
4390 };
4391 requestBody?: never;
4392 responses: {
4393 /** @description Audit log entries */
4394 200: {
4395 headers: {
4396 [name: string]: unknown;
4397 };
4398 content: {
4399 "application/json": {
4400 items: components["schemas"]["AuditLogEntry"][];
4401 next_cursor: string | null;
4402 };
4403 };
4404 };
4405 };
4406 };
4407 put?: never;
4408 post?: never;
4409 delete?: never;
4410 options?: never;
4411 head?: never;
4412 patch?: never;
4413 trace?: never;
4414 };
4415 "/api/v1/playbooks": {
4416 parameters: {
4417 query?: never;
4418 header?: never;
4419 path?: never;
4420 cookie?: never;
4421 };
4422 /**
4423 * List playbooks visible to the caller (M3-A4)
4424 * @description Returns playbooks the caller can see: admins see all;
4425 * non-admins see playbooks they authored or built-in playbooks
4426 * (``created_by IS NULL``). Soft-deleted rows (``deleted_at IS NOT
4427 * NULL``) are excluded for everyone, including admins. Positions
4428 * are NOT inlined; clients call ``GET /api/v1/playbooks/{id}`` to
4429 * fetch them.
4430 */
4431 get: {
4432 parameters: {
4433 query?: never;
4434 header?: never;
4435 path?: never;
4436 cookie?: never;
4437 };
4438 requestBody?: never;
4439 responses: {
4440 /** @description List of playbooks (positions empty). */
4441 200: {
4442 headers: {
4443 [name: string]: unknown;
4444 };
4445 content: {
4446 "application/json": components["schemas"]["Playbook"][];
4447 };
4448 };
4449 /** @description Not authenticated. */
4450 401: {
4451 headers: {
4452 [name: string]: unknown;
4453 };
4454 content?: never;
4455 };
4456 };
4457 };
4458 put?: never;
4459 /**
4460 * Create a new playbook (M3-A6)
4461 * @description Creates a playbook owned by the caller (``created_by =
4462 * caller.id``). Admins do not get to mint built-ins through this
4463 * endpoint — built-ins (``created_by IS NULL``) ship via seed
4464 * migration only. The Inference-Tier and audit posture matches
4465 * other write endpoints on the API.
4466 */
4467 post: {
4468 parameters: {
4469 query?: never;
4470 header?: never;
4471 path?: never;
4472 cookie?: never;
4473 };
4474 requestBody: {
4475 content: {
4476 "application/json": components["schemas"]["PlaybookCreate"];
4477 };
4478 };
4479 responses: {
4480 /** @description Playbook created. Body includes the assembled positions. */
4481 201: {
4482 headers: {
4483 [name: string]: unknown;
4484 };
4485 content: {
4486 "application/json": components["schemas"]["Playbook"];
4487 };
4488 };
4489 /** @description Not authenticated. */
4490 401: {
4491 headers: {
4492 [name: string]: unknown;
4493 };
4494 content?: never;
4495 };
4496 /** @description Validation error (e.g., unknown field, invalid severity enum). */
4497 422: {
4498 headers: {
4499 [name: string]: unknown;
4500 };
4501 content?: never;
4502 };
4503 };
4504 };
4505 delete?: never;
4506 options?: never;
4507 head?: never;
4508 patch?: never;
4509 trace?: never;
4510 };
4511 "/api/v1/playbooks/{playbook_id}": {
4512 parameters: {
4513 query?: never;
4514 header?: never;
4515 path: {
4516 playbook_id: string;
4517 };
4518 cookie?: never;
4519 };
4520 /**
4521 * Get a playbook with its full position list (M3-A4)
4522 * @description Returns the playbook header + positions + fallback tiers.
4523 * Visibility matches ``GET /api/v1/playbooks``. 404 (not 403)
4524 * on unauthorized access, including for soft-deleted rows.
4525 */
4526 get: {
4527 parameters: {
4528 query?: never;
4529 header?: never;
4530 path: {
4531 playbook_id: string;
4532 };
4533 cookie?: never;
4534 };
4535 requestBody?: never;
4536 responses: {
4537 /** @description Full playbook with positions. */
4538 200: {
4539 headers: {
4540 [name: string]: unknown;
4541 };
4542 content: {
4543 "application/json": components["schemas"]["Playbook"];
4544 };
4545 };
4546 /** @description Not authenticated. */
4547 401: {
4548 headers: {
4549 [name: string]: unknown;
4550 };
4551 content?: never;
4552 };
4553 /** @description Playbook not found, or caller is not authorized to see it. */
4554 404: {
4555 headers: {
4556 [name: string]: unknown;
4557 };
4558 content?: never;
4559 };
4560 };
4561 };
4562 put?: never;
4563 post?: never;
4564 /**
4565 * Soft-delete a playbook (M3-A6)
4566 * @description Sets ``deleted_at`` on the row. The ``playbook_positions`` rows
4567 * remain so historical executions still resolve their position
4568 * references. Authorization mirrors PATCH: built-ins are 403;
4569 * non-built-ins require admin OR ownership; cross-user / already-
4570 * deleted is 404. Subsequent reads (GET, list) treat the row as
4571 * absent.
4572 */
4573 delete: {
4574 parameters: {
4575 query?: never;
4576 header?: never;
4577 path: {
4578 playbook_id: string;
4579 };
4580 cookie?: never;
4581 };
4582 requestBody?: never;
4583 responses: {
4584 /** @description Playbook soft-deleted. */
4585 204: {
4586 headers: {
4587 [name: string]: unknown;
4588 };
4589 content?: never;
4590 };
4591 /** @description Not authenticated. */
4592 401: {
4593 headers: {
4594 [name: string]: unknown;
4595 };
4596 content?: never;
4597 };
4598 /** @description Built-in playbooks cannot be deleted through this endpoint. */
4599 403: {
4600 headers: {
4601 [name: string]: unknown;
4602 };
4603 content?: never;
4604 };
4605 /** @description Playbook not found, already soft-deleted, or not authorized. */
4606 404: {
4607 headers: {
4608 [name: string]: unknown;
4609 };
4610 content?: never;
4611 };
4612 };
4613 };
4614 options?: never;
4615 head?: never;
4616 /**
4617 * Update a playbook header; optionally replace positions (M3-A6)
4618 * @description Patches the playbook. Authorization:
4619 *
4620 * * Built-in playbooks (``created_by IS NULL``) are 403 to
4621 * everyone, including admins — operators fork-then-edit. This
4622 * keeps shared deployment-level content immutable to a single
4623 * operator's mistake.
4624 * * Non-built-in playbooks can be patched by the playbook's author
4625 * OR by an admin. Cross-user / soft-deleted cases return 404.
4626 *
4627 * Position replacement is atomic: when ``positions`` is supplied,
4628 * every existing position row for this playbook is deleted and
4629 * the new list is inserted in a single transaction.
4630 */
4631 patch: {
4632 parameters: {
4633 query?: never;
4634 header?: never;
4635 path: {
4636 playbook_id: string;
4637 };
4638 cookie?: never;
4639 };
4640 requestBody: {
4641 content: {
4642 "application/json": components["schemas"]["PlaybookUpdate"];
4643 };
4644 };
4645 responses: {
4646 /** @description Playbook updated; response is the fresh full shape. */
4647 200: {
4648 headers: {
4649 [name: string]: unknown;
4650 };
4651 content: {
4652 "application/json": components["schemas"]["Playbook"];
4653 };
4654 };
4655 /** @description Not authenticated. */
4656 401: {
4657 headers: {
4658 [name: string]: unknown;
4659 };
4660 content?: never;
4661 };
4662 /** @description Built-in playbooks cannot be edited through this endpoint. */
4663 403: {
4664 headers: {
4665 [name: string]: unknown;
4666 };
4667 content?: never;
4668 };
4669 /** @description Playbook not found, soft-deleted, or not authorized. */
4670 404: {
4671 headers: {
4672 [name: string]: unknown;
4673 };
4674 content?: never;
4675 };
4676 /** @description Validation error. */
4677 422: {
4678 headers: {
4679 [name: string]: unknown;
4680 };
4681 content?: never;
4682 };
4683 };
4684 };
4685 trace?: never;
4686 };
4687 "/api/v1/playbooks/easy": {
4688 parameters: {
4689 query?: never;
4690 header?: never;
4691 path?: never;
4692 cookie?: never;
4693 };
4694 get?: never;
4695 put?: never;
4696 /**
4697 * Start an Easy Playbook generation run (M3-A6)
4698 * @description Kicks off the Easy Playbook auto-generation pipeline against
4699 * the supplied document corpus. Creates an
4700 * ``EasyPlaybookGeneration`` row at ``status='pending'`` and
4701 * enqueues the ARQ worker job on the ``arq:m3a6`` queue (the
4702 * dedicated M3-A6 worker — see ``app/workers/arq_setup.py``).
4703 * Returns 202 immediately; the wizard's Step 2 polls
4704 * ``GET /api/v1/playbooks/easy/{generation_id}`` until status
4705 * reaches a terminal value.
4706 *
4707 * Authorization: caller must own every document in
4708 * ``document_ids`` (admins bypass). Cross-user / missing /
4709 * soft-deleted documents collapse into 404.
4710 *
4711 * Generation completion does NOT mean the playbook is fit for
4712 * use; the wizard's Step 3 inline editor is where the user-
4713 * attorney validates and edits before the final save (which
4714 * POSTs to ``/api/v1/playbooks`` like any other playbook).
4715 */
4716 post: {
4717 parameters: {
4718 query?: never;
4719 header?: never;
4720 path?: never;
4721 cookie?: never;
4722 };
4723 requestBody: {
4724 content: {
4725 "application/json": components["schemas"]["EasyPlaybookGenerationCreate"];
4726 };
4727 };
4728 responses: {
4729 /** @description Generation scheduled; row created at status `pending`. */
4730 202: {
4731 headers: {
4732 [name: string]: unknown;
4733 };
4734 content: {
4735 "application/json": components["schemas"]["EasyPlaybookGeneration"];
4736 };
4737 };
4738 /** @description Not authenticated. */
4739 401: {
4740 headers: {
4741 [name: string]: unknown;
4742 };
4743 content?: never;
4744 };
4745 /** @description One or more documents not found / not authorized. */
4746 404: {
4747 headers: {
4748 [name: string]: unknown;
4749 };
4750 content?: never;
4751 };
4752 /** @description Validation error (empty ``document_ids``, unknown field, etc.). */
4753 422: {
4754 headers: {
4755 [name: string]: unknown;
4756 };
4757 content?: never;
4758 };
4759 };
4760 };
4761 delete?: never;
4762 options?: never;
4763 head?: never;
4764 patch?: never;
4765 trace?: never;
4766 };
4767 "/api/v1/playbooks/easy/{generation_id}": {
4768 parameters: {
4769 query?: never;
4770 header?: never;
4771 path: {
4772 generation_id: string;
4773 };
4774 cookie?: never;
4775 };
4776 /**
4777 * Poll an Easy Playbook generation row (M3-A6)
4778 * @description Returns the current state of one Easy Playbook generation.
4779 * Caller must be the row's user OR an admin; cross-user / missing
4780 * rows return 404.
4781 *
4782 * When ``status='completed'``, ``draft_playbook`` carries the
4783 * assembled ``PlaybookCreate`` shape — the wizard's Step 3 inline
4784 * editor binds to this. When ``status='error'``, ``error_message``
4785 * is populated. The wizard's Step 2 polls every few seconds until
4786 * a terminal status arrives.
4787 */
4788 get: {
4789 parameters: {
4790 query?: never;
4791 header?: never;
4792 path: {
4793 generation_id: string;
4794 };
4795 cookie?: never;
4796 };
4797 requestBody?: never;
4798 responses: {
4799 /** @description Current generation row. */
4800 200: {
4801 headers: {
4802 [name: string]: unknown;
4803 };
4804 content: {
4805 "application/json": components["schemas"]["EasyPlaybookGeneration"];
4806 };
4807 };
4808 /** @description Not authenticated. */
4809 401: {
4810 headers: {
4811 [name: string]: unknown;
4812 };
4813 content?: never;
4814 };
4815 /** @description Generation not found or not authorized. */
4816 404: {
4817 headers: {
4818 [name: string]: unknown;
4819 };
4820 content?: never;
4821 };
4822 };
4823 };
4824 put?: never;
4825 post?: never;
4826 delete?: never;
4827 options?: never;
4828 head?: never;
4829 patch?: never;
4830 trace?: never;
4831 };
4832 "/api/v1/tabular/preview-cost": {
4833 parameters: {
4834 query?: never;
4835 header?: never;
4836 path?: never;
4837 cookie?: never;
4838 };
4839 get?: never;
4840 put?: never;
4841 /**
4842 * Preview the cost of a proposed tabular execution (M3-C2)
4843 * @description Synchronous cost preview — no execution row is created. The UI
4844 * calls this before showing the confirmation modal so the
4845 * operator sees the cell-count + estimated cost + per-tier
4846 * breakdown (Phase C prep doc Decision C-5).
4847 *
4848 * Either ``skill_name`` or ``columns`` is required (not both).
4849 * The estimator uses a rolling-average over recent
4850 * ``purpose='tabular_extraction'`` routing-log rows; cold-start
4851 * deployments see the conservative default per-cell cost until
4852 * enough calibration data accumulates.
4853 */
4854 post: {
4855 parameters: {
4856 query?: never;
4857 header?: never;
4858 path?: never;
4859 cookie?: never;
4860 };
4861 requestBody: {
4862 content: {
4863 "application/json": components["schemas"]["TabularPreviewCostRequest"];
4864 };
4865 };
4866 responses: {
4867 /** @description Cost preview. */
4868 200: {
4869 headers: {
4870 [name: string]: unknown;
4871 };
4872 content: {
4873 "application/json": components["schemas"]["TabularPreviewCostResponse"];
4874 };
4875 };
4876 /** @description Both ``skill_name`` and ``columns`` provided, or skill has no columns. */
4877 400: {
4878 headers: {
4879 [name: string]: unknown;
4880 };
4881 content?: never;
4882 };
4883 /** @description Not authenticated. */
4884 401: {
4885 headers: {
4886 [name: string]: unknown;
4887 };
4888 content?: never;
4889 };
4890 /** @description ``skill_name`` not found in the live skill registry. */
4891 404: {
4892 headers: {
4893 [name: string]: unknown;
4894 };
4895 content?: never;
4896 };
4897 /** @description Validation error (empty ``document_ids``, malformed column spec, etc.). */
4898 422: {
4899 headers: {
4900 [name: string]: unknown;
4901 };
4902 content?: never;
4903 };
4904 };
4905 };
4906 delete?: never;
4907 options?: never;
4908 head?: never;
4909 patch?: never;
4910 trace?: never;
4911 };
4912 "/api/v1/tabular/execute": {
4913 parameters: {
4914 query?: never;
4915 header?: never;
4916 path?: never;
4917 cookie?: never;
4918 };
4919 get?: never;
4920 put?: never;
4921 /**
4922 * Start a tabular execution (M3-C2)
4923 * @description Kicks off a tabular execution against the supplied document
4924 * corpus. Creates a ``TabularExecution`` row at
4925 * ``status='pending'`` and enqueues the ARQ worker job on the
4926 * shared playbook queue (per Decision C-3 — same queue as Easy
4927 * Playbook). Returns 202 immediately; the result view polls
4928 * ``GET /api/v1/tabular/executions/{id}`` until status reaches
4929 * a terminal value.
4930 *
4931 * Authorization: caller must own every document in
4932 * ``document_ids`` (admins bypass). Cross-user / missing /
4933 * soft-deleted documents collapse into 404.
4934 *
4935 * Execution completion does NOT mean every cell is correct —
4936 * the result view's per-cell citation drawer is where the
4937 * user-attorney validates extractions before relying on them.
4938 */
4939 post: {
4940 parameters: {
4941 query?: never;
4942 header?: never;
4943 path?: never;
4944 cookie?: never;
4945 };
4946 requestBody: {
4947 content: {
4948 "application/json": components["schemas"]["TabularExecutionCreate"];
4949 };
4950 };
4951 responses: {
4952 /** @description Execution scheduled; row created at status `pending`. */
4953 202: {
4954 headers: {
4955 [name: string]: unknown;
4956 };
4957 content: {
4958 "application/json": components["schemas"]["TabularExecution"];
4959 };
4960 };
4961 /** @description Both ``skill_name`` and ``columns`` provided, or skill has no columns. */
4962 400: {
4963 headers: {
4964 [name: string]: unknown;
4965 };
4966 content?: never;
4967 };
4968 /** @description Not authenticated. */
4969 401: {
4970 headers: {
4971 [name: string]: unknown;
4972 };
4973 content?: never;
4974 };
4975 /** @description One or more documents not found / not authorized, or skill not found. */
4976 404: {
4977 headers: {
4978 [name: string]: unknown;
4979 };
4980 content?: never;
4981 };
4982 /** @description Validation error. */
4983 422: {
4984 headers: {
4985 [name: string]: unknown;
4986 };
4987 content?: never;
4988 };
4989 };
4990 };
4991 delete?: never;
4992 options?: never;
4993 head?: never;
4994 patch?: never;
4995 trace?: never;
4996 };
4997 "/api/v1/tabular/executions": {
4998 parameters: {
4999 query?: never;
5000 header?: never;
5001 path?: never;
5002 cookie?: never;
5003 };
5004 /**
5005 * List the caller's tabular executions (M3-C2)
5006 * @description Returns the caller's tabular executions in recent-first order.
5007 * Soft-deleted rows are excluded. Admins see all rows; non-admins
5008 * see only their own.
5009 */
5010 get: {
5011 parameters: {
5012 query?: {
5013 /** @description Maximum rows to return; default 50. */
5014 limit?: number;
5015 };
5016 header?: never;
5017 path?: never;
5018 cookie?: never;
5019 };
5020 requestBody?: never;
5021 responses: {
5022 /** @description List of tabular execution summaries. */
5023 200: {
5024 headers: {
5025 [name: string]: unknown;
5026 };
5027 content: {
5028 "application/json": components["schemas"]["TabularExecutionSummary"][];
5029 };
5030 };
5031 /** @description Not authenticated. */
5032 401: {
5033 headers: {
5034 [name: string]: unknown;
5035 };
5036 content?: never;
5037 };
5038 };
5039 };
5040 put?: never;
5041 post?: never;
5042 delete?: never;
5043 options?: never;
5044 head?: never;
5045 patch?: never;
5046 trace?: never;
5047 };
5048 "/api/v1/tabular/executions/{execution_id}": {
5049 parameters: {
5050 query?: never;
5051 header?: never;
5052 path: {
5053 execution_id: string;
5054 };
5055 cookie?: never;
5056 };
5057 /**
5058 * Get a tabular execution by id (M3-C2)
5059 * @description Returns the full execution — status, results grid, costs,
5060 * timing. Caller must be the row's user OR an admin; cross-user
5061 * / missing / soft-deleted rows return 404.
5062 */
5063 get: {
5064 parameters: {
5065 query?: never;
5066 header?: never;
5067 path: {
5068 execution_id: string;
5069 };
5070 cookie?: never;
5071 };
5072 requestBody?: never;
5073 responses: {
5074 /** @description Current execution row. */
5075 200: {
5076 headers: {
5077 [name: string]: unknown;
5078 };
5079 content: {
5080 "application/json": components["schemas"]["TabularExecution"];
5081 };
5082 };
5083 /** @description Not authenticated. */
5084 401: {
5085 headers: {
5086 [name: string]: unknown;
5087 };
5088 content?: never;
5089 };
5090 /** @description Execution not found or not authorized. */
5091 404: {
5092 headers: {
5093 [name: string]: unknown;
5094 };
5095 content?: never;
5096 };
5097 };
5098 };
5099 put?: never;
5100 post?: never;
5101 /**
5102 * Soft-delete a tabular execution (M3-C2)
5103 * @description Sets ``deleted_at`` to now. Soft-deleted rows are invisible
5104 * to list / get / cancel endpoints; subsequent operations
5105 * return 404.
5106 */
5107 delete: {
5108 parameters: {
5109 query?: never;
5110 header?: never;
5111 path: {
5112 execution_id: string;
5113 };
5114 cookie?: never;
5115 };
5116 requestBody?: never;
5117 responses: {
5118 /** @description Soft-deleted. */
5119 204: {
5120 headers: {
5121 [name: string]: unknown;
5122 };
5123 content?: never;
5124 };
5125 /** @description Not authenticated. */
5126 401: {
5127 headers: {
5128 [name: string]: unknown;
5129 };
5130 content?: never;
5131 };
5132 /** @description Execution not found or already deleted. */
5133 404: {
5134 headers: {
5135 [name: string]: unknown;
5136 };
5137 content?: never;
5138 };
5139 };
5140 };
5141 options?: never;
5142 head?: never;
5143 patch?: never;
5144 trace?: never;
5145 };
5146 "/api/v1/tabular/executions/{execution_id}/cancel": {
5147 parameters: {
5148 query?: never;
5149 header?: never;
5150 path: {
5151 execution_id: string;
5152 };
5153 cookie?: never;
5154 };
5155 get?: never;
5156 put?: never;
5157 /**
5158 * Cancel a pending or running tabular execution (M3-C2)
5159 * @description Sets status to ``cancelled`` and ``completed_at`` to now.
5160 * The worker's per-cell loop checks the row status at each
5161 * cell-iteration boundary; on cancellation it stops accepting
5162 * new cells and the aggregate node writes whatever partial
5163 * results landed. Terminal rows (``completed`` / ``failed`` /
5164 * ``cancelled``) return 409 — operators wanting a clean re-run
5165 * start a new execution via ``POST /tabular/execute``.
5166 */
5167 post: {
5168 parameters: {
5169 query?: never;
5170 header?: never;
5171 path: {
5172 execution_id: string;
5173 };
5174 cookie?: never;
5175 };
5176 requestBody?: never;
5177 responses: {
5178 /** @description Cancellation accepted; row updated. */
5179 200: {
5180 headers: {
5181 [name: string]: unknown;
5182 };
5183 content: {
5184 "application/json": components["schemas"]["TabularExecution"];
5185 };
5186 };
5187 /** @description Not authenticated. */
5188 401: {
5189 headers: {
5190 [name: string]: unknown;
5191 };
5192 content?: never;
5193 };
5194 /** @description Execution not found or not authorized. */
5195 404: {
5196 headers: {
5197 [name: string]: unknown;
5198 };
5199 content?: never;
5200 };
5201 /** @description Execution already in a terminal status. */
5202 409: {
5203 headers: {
5204 [name: string]: unknown;
5205 };
5206 content?: never;
5207 };
5208 };
5209 };
5210 delete?: never;
5211 options?: never;
5212 head?: never;
5213 patch?: never;
5214 trace?: never;
5215 };
5216 "/api/v1/tabular/executions/{execution_id}/export": {
5217 parameters: {
5218 query?: never;
5219 header?: never;
5220 path: {
5221 execution_id: string;
5222 };
5223 cookie?: never;
5224 };
5225 /**
5226 * Export a completed tabular grid as XLSX or CSV (M3-C4a)
5227 * @description Streams the tabular grid in the requested format. Both formats
5228 * carry the document column (leftmost) plus one column per declared
5229 * column spec, in spec order. Cells with ``confidence='failed'``
5230 * render as ``"(failed)"`` so operators can spot gaps.
5231 *
5232 * Citation surfacing differs by format:
5233 *
5234 * * **XLSX** — each grid cell with at least one citation carries an
5235 * openpyxl cell ``Comment`` listing the citation ids + confidences
5236 * (up to 5 per comment; the cell retains the full count). Operators
5237 * hover any cell in Excel / Numbers / Google Sheets to see sources.
5238 * * **CSV** — a trailing ``citation_links`` column per row carries a
5239 * semicolon-separated list of ``"<column_name>:<citation_id>"``
5240 * pairs across the row's cells; empty when no cell had citations.
5241 *
5242 * The execution must be in ``status='completed'`` — pending /
5243 * running / cancelled / failed rows return 409 (partial grids would
5244 * mislead downstream consumers).
5245 */
5246 get: {
5247 parameters: {
5248 query?: {
5249 /** @description Export format. `xlsx` carries citations as cell comments; `csv` flattens them into a `citation_links` column. */
5250 format?: "xlsx" | "csv";
5251 };
5252 header?: never;
5253 path: {
5254 execution_id: string;
5255 };
5256 cookie?: never;
5257 };
5258 requestBody?: never;
5259 responses: {
5260 /** @description Streaming export; `Content-Type` matches the format. */
5261 200: {
5262 headers: {
5263 [name: string]: unknown;
5264 };
5265 content: {
5266 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": string;
5267 "text/csv": string;
5268 };
5269 };
5270 /** @description Not authenticated. */
5271 401: {
5272 headers: {
5273 [name: string]: unknown;
5274 };
5275 content?: never;
5276 };
5277 /** @description Execution not found or not authorized. */
5278 404: {
5279 headers: {
5280 [name: string]: unknown;
5281 };
5282 content?: never;
5283 };
5284 /** @description Execution not in a terminal `completed` status — cannot export. */
5285 409: {
5286 headers: {
5287 [name: string]: unknown;
5288 };
5289 content?: never;
5290 };
5291 };
5292 };
5293 put?: never;
5294 post?: never;
5295 delete?: never;
5296 options?: never;
5297 head?: never;
5298 patch?: never;
5299 trace?: never;
5300 };
5301 "/api/v1/playbooks/{playbook_id}/execute": {
5302 parameters: {
5303 query?: never;
5304 header?: never;
5305 path: {
5306 playbook_id: string;
5307 };
5308 cookie?: never;
5309 };
5310 get?: never;
5311 put?: never;
5312 /**
5313 * Kick off a playbook execution against a target document (M3-A2)
5314 * @description Creates a new ``playbook_executions`` row at status ``'pending'``
5315 * and schedules the four-node LangGraph workflow
5316 * (retrieve → classify → redline → compile) as a FastAPI
5317 * BackgroundTask. The response returns immediately (202) with the
5318 * new row; clients poll
5319 * ``GET /api/v1/playbook-executions/{execution_id}`` until they
5320 * see a terminal status (``completed`` or ``error``).
5321 *
5322 * Authorization: caller must be an admin or the playbook's
5323 * author, and own the target document's parent file. If
5324 * ``project_id`` is supplied, caller must also own the project.
5325 */
5326 post: {
5327 parameters: {
5328 query?: never;
5329 header?: never;
5330 path: {
5331 playbook_id: string;
5332 };
5333 cookie?: never;
5334 };
5335 requestBody: {
5336 content: {
5337 "application/json": {
5338 /** Format: uuid */
5339 target_document_id: string;
5340 /** Format: uuid */
5341 project_id?: string | null;
5342 };
5343 };
5344 };
5345 responses: {
5346 /** @description Execution scheduled; row created at status `pending`. */
5347 202: {
5348 headers: {
5349 [name: string]: unknown;
5350 };
5351 content: {
5352 "application/json": components["schemas"]["PlaybookExecution"];
5353 };
5354 };
5355 /** @description Not authenticated. */
5356 401: {
5357 headers: {
5358 [name: string]: unknown;
5359 };
5360 content: {
5361 "application/json": components["schemas"]["Error"];
5362 };
5363 };
5364 /** @description Playbook, target document, or project not found / not owned. */
5365 404: {
5366 headers: {
5367 [name: string]: unknown;
5368 };
5369 content: {
5370 "application/json": components["schemas"]["Error"];
5371 };
5372 };
5373 /** @description Request body validation error (e.g., missing or malformed `target_document_id`, unknown field). */
5374 422: {
5375 headers: {
5376 [name: string]: unknown;
5377 };
5378 content: {
5379 "application/json": components["schemas"]["Error"];
5380 };
5381 };
5382 };
5383 };
5384 delete?: never;
5385 options?: never;
5386 head?: never;
5387 patch?: never;
5388 trace?: never;
5389 };
5390 "/api/v1/playbook-executions/{execution_id}": {
5391 parameters: {
5392 query?: never;
5393 header?: never;
5394 path: {
5395 execution_id: string;
5396 };
5397 cookie?: never;
5398 };
5399 /**
5400 * Poll the current state of a playbook execution (M3-A2)
5401 * @description Returns the row regardless of completion state. Callers poll
5402 * until they see a terminal ``completed`` or ``error`` status.
5403 * Authorization: caller must own the execution (``user_id``
5404 * match) or be an admin.
5405 */
5406 get: {
5407 parameters: {
5408 query?: never;
5409 header?: never;
5410 path: {
5411 execution_id: string;
5412 };
5413 cookie?: never;
5414 };
5415 requestBody?: never;
5416 responses: {
5417 /** @description Current execution state. */
5418 200: {
5419 headers: {
5420 [name: string]: unknown;
5421 };
5422 content: {
5423 "application/json": components["schemas"]["PlaybookExecution"];
5424 };
5425 };
5426 /** @description Not authenticated. */
5427 401: {
5428 headers: {
5429 [name: string]: unknown;
5430 };
5431 content: {
5432 "application/json": components["schemas"]["Error"];
5433 };
5434 };
5435 /** @description Execution not found or caller does not own it. */
5436 404: {
5437 headers: {
5438 [name: string]: unknown;
5439 };
5440 content: {
5441 "application/json": components["schemas"]["Error"];
5442 };
5443 };
5444 };
5445 };
5446 put?: never;
5447 post?: never;
5448 delete?: never;
5449 options?: never;
5450 head?: never;
5451 patch?: never;
5452 trace?: never;
5453 };
5454 "/api/v1/admin/ingest-health": {
5455 parameters: {
5456 query?: never;
5457 header?: never;
5458 path?: never;
5459 cookie?: never;
5460 };
5461 /**
5462 * Aggregate ingest-status counts across the deployment (admin-only)
5463 * @description Reports document-level + file-level ingest health in a single
5464 * response: ``ok`` (chunks embedded), ``embed_failed`` /
5465 * ``partial`` (document-level post-parse failures introduced by
5466 * M3-0.3 / DE-276), and ``parse_failed`` (file-level parse
5467 * failures from the M1 pipeline). Soft-deleted rows are excluded.
5468 *
5469 * A non-zero ``embed_failed`` or ``partial`` count is the
5470 * operator's canonical signal that hybrid retrieval has silently
5471 * degraded for some documents — the exact failure mode DE-276
5472 * was filed to surface. A non-zero ``parse_failed`` count means
5473 * operators should inspect the file-list UI for the specific
5474 * failures.
5475 */
5476 get: {
5477 parameters: {
5478 query?: never;
5479 header?: never;
5480 path?: never;
5481 cookie?: never;
5482 };
5483 requestBody?: never;
5484 responses: {
5485 /** @description Aggregate ingest-health summary */
5486 200: {
5487 headers: {
5488 [name: string]: unknown;
5489 };
5490 content: {
5491 "application/json": {
5492 /** @description Documents with all chunks successfully embedded. */
5493 ok: number;
5494 /**
5495 * @description Documents whose embed worker raised before any chunk
5496 * was embedded — hybrid retrieval falls back to FTS-only.
5497 */
5498 embed_failed: number;
5499 /**
5500 * @description Documents whose embed worker raised mid-batch — some
5501 * chunks have vectors, others are NULL.
5502 */
5503 partial: number;
5504 /**
5505 * @description Files that failed at parse time and never produced a
5506 * ``documents`` row (``files.ingestion_status='failed'``).
5507 */
5508 parse_failed: number;
5509 /** @description Sum of ok + embed_failed + partial. */
5510 total_documents: number;
5511 };
5512 };
5513 };
5514 /** @description Caller is not an admin */
5515 403: {
5516 headers: {
5517 [name: string]: unknown;
5518 };
5519 content: {
5520 "application/json": components["schemas"]["Error"];
5521 };
5522 };
5523 };
5524 };
5525 put?: never;
5526 post?: never;
5527 delete?: never;
5528 options?: never;
5529 head?: never;
5530 patch?: never;
5531 trace?: never;
5532 };
5533 "/api/v1/admin/bootstrap-status": {
5534 parameters: {
5535 query?: never;
5536 header?: never;
5537 path?: never;
5538 cookie?: never;
5539 };
5540 /**
5541 * Report whether the first-run bootstrap admin password is still active
5542 * @description **Unauthenticated.** Consulted by the login UI before the operator
5543 * has credentials, so it can render a fresh-install hint pointing at
5544 * the API container logs when the bootstrap password has not yet
5545 * been rotated (M3-0.1 / DE-283).
5546 *
5547 * ``default_password_active`` is True when at least one non-deleted
5548 * admin user still has ``must_change_password=True``. The flag flips
5549 * to False once the operator hits ``POST /api/v1/auth/change-password``,
5550 * at which point the login UI stops surfacing the hint.
5551 *
5552 * The signal exposed by this endpoint is low-sensitivity: the
5553 * bootstrap password is 24 characters of CSPRNG output, so knowing
5554 * a deployment is in fresh-install state does not measurably help
5555 * an attacker who lacks the log line.
5556 */
5557 get: {
5558 parameters: {
5559 query?: never;
5560 header?: never;
5561 path?: never;
5562 cookie?: never;
5563 };
5564 requestBody?: never;
5565 responses: {
5566 /** @description Bootstrap state */
5567 200: {
5568 headers: {
5569 [name: string]: unknown;
5570 };
5571 content: {
5572 "application/json": {
5573 /**
5574 * @description True when at least one admin user is still in the
5575 * ``must_change_password=True`` state, indicating the
5576 * first-run bootstrap password has not been rotated.
5577 */
5578 default_password_active: boolean;
5579 /**
5580 * @description Shell command an operator can run to retrieve the
5581 * bootstrap password from the API container's logs.
5582 */
5583 logs_hint: string;
5584 };
5585 };
5586 };
5587 };
5588 };
5589 put?: never;
5590 post?: never;
5591 delete?: never;
5592 options?: never;
5593 head?: never;
5594 patch?: never;
5595 trace?: never;
5596 };
5597 "/api/v1/admin/aliases": {
5598 parameters: {
5599 query?: never;
5600 header?: never;
5601 path?: never;
5602 cookie?: never;
5603 };
5604 /**
5605 * List configured model aliases (admin only)
5606 * @description Proxies the gateway's ``/admin/v1/aliases`` surface. The user's
5607 * bearer token must have ``is_admin = true`` or the endpoint
5608 * returns 403 ``forbidden``.
5609 */
5610 get: {
5611 parameters: {
5612 query?: never;
5613 header?: never;
5614 path?: never;
5615 cookie?: never;
5616 };
5617 requestBody?: never;
5618 responses: {
5619 /** @description Alias list */
5620 200: {
5621 headers: {
5622 [name: string]: unknown;
5623 };
5624 content: {
5625 "application/json": {
5626 /** @enum {string} */
5627 object: "list";
5628 data: components["schemas"]["AdminAliasEntry"][];
5629 };
5630 };
5631 };
5632 /** @description Caller is not an admin */
5633 403: {
5634 headers: {
5635 [name: string]: unknown;
5636 };
5637 content: {
5638 "application/json": components["schemas"]["Error"];
5639 };
5640 };
5641 };
5642 };
5643 put?: never;
5644 /** Create a new model alias (admin only) */
5645 post: {
5646 parameters: {
5647 query?: never;
5648 header?: never;
5649 path?: never;
5650 cookie?: never;
5651 };
5652 requestBody: {
5653 content: {
5654 "application/json": components["schemas"]["AdminAliasCreate"];
5655 };
5656 };
5657 responses: {
5658 /** @description Alias created */
5659 201: {
5660 headers: {
5661 [name: string]: unknown;
5662 };
5663 content: {
5664 "application/json": components["schemas"]["AdminAliasEntry"];
5665 };
5666 };
5667 /** @description Alias name already configured */
5668 409: {
5669 headers: {
5670 [name: string]: unknown;
5671 };
5672 content: {
5673 "application/json": components["schemas"]["Error"];
5674 };
5675 };
5676 };
5677 };
5678 delete?: never;
5679 options?: never;
5680 head?: never;
5681 patch?: never;
5682 trace?: never;
5683 };
5684 "/api/v1/admin/aliases/{name}": {
5685 parameters: {
5686 query?: never;
5687 header?: never;
5688 path: {
5689 name: string;
5690 };
5691 cookie?: never;
5692 };
5693 /** Get a single alias (admin only) */
5694 get: {
5695 parameters: {
5696 query?: never;
5697 header?: never;
5698 path: {
5699 name: string;
5700 };
5701 cookie?: never;
5702 };
5703 requestBody?: never;
5704 responses: {
5705 /** @description Alias detail */
5706 200: {
5707 headers: {
5708 [name: string]: unknown;
5709 };
5710 content: {
5711 "application/json": components["schemas"]["AdminAliasEntry"];
5712 };
5713 };
5714 /** @description Alias not configured */
5715 404: {
5716 headers: {
5717 [name: string]: unknown;
5718 };
5719 content: {
5720 "application/json": components["schemas"]["Error"];
5721 };
5722 };
5723 };
5724 };
5725 put?: never;
5726 post?: never;
5727 /** Remove an alias (admin only) */
5728 delete: {
5729 parameters: {
5730 query?: never;
5731 header?: never;
5732 path: {
5733 name: string;
5734 };
5735 cookie?: never;
5736 };
5737 requestBody?: never;
5738 responses: {
5739 /** @description Alias removed */
5740 204: {
5741 headers: {
5742 [name: string]: unknown;
5743 };
5744 content?: never;
5745 };
5746 /** @description Alias not configured */
5747 404: {
5748 headers: {
5749 [name: string]: unknown;
5750 };
5751 content: {
5752 "application/json": components["schemas"]["Error"];
5753 };
5754 };
5755 };
5756 };
5757 options?: never;
5758 head?: never;
5759 /** Update an alias (admin only) */
5760 patch: {
5761 parameters: {
5762 query?: never;
5763 header?: never;
5764 path: {
5765 name: string;
5766 };
5767 cookie?: never;
5768 };
5769 requestBody: {
5770 content: {
5771 "application/json": components["schemas"]["AdminAliasUpdate"];
5772 };
5773 };
5774 responses: {
5775 /** @description Alias updated */
5776 200: {
5777 headers: {
5778 [name: string]: unknown;
5779 };
5780 content: {
5781 "application/json": components["schemas"]["AdminAliasEntry"];
5782 };
5783 };
5784 /** @description Alias not configured */
5785 404: {
5786 headers: {
5787 [name: string]: unknown;
5788 };
5789 content: {
5790 "application/json": components["schemas"]["Error"];
5791 };
5792 };
5793 };
5794 };
5795 trace?: never;
5796 };
5797 "/api/v1/admin/provider-keys": {
5798 parameters: {
5799 query?: never;
5800 header?: never;
5801 path?: never;
5802 cookie?: never;
5803 };
5804 /**
5805 * List provider-key status (admin only)
5806 * @description Donna #7 (runtime BYOK). Proxies the gateway's
5807 * ``/admin/v1/provider-keys`` surface. The backend holds the
5808 * gateway-key; the frontend never does. Returns a secret-safe status
5809 * row per configured provider — the response NEVER contains a full
5810 * key, only the last 4 characters of a resolved key. The caller's
5811 * bearer token must have ``is_admin = true`` or the endpoint returns
5812 * 403 ``forbidden``.
5813 */
5814 get: {
5815 parameters: {
5816 query?: never;
5817 header?: never;
5818 path?: never;
5819 cookie?: never;
5820 };
5821 requestBody?: never;
5822 responses: {
5823 /** @description Provider-key status list */
5824 200: {
5825 headers: {
5826 [name: string]: unknown;
5827 };
5828 content: {
5829 "application/json": components["schemas"]["ProviderKeyList"];
5830 };
5831 };
5832 /** @description Caller is not an admin */
5833 403: {
5834 headers: {
5835 [name: string]: unknown;
5836 };
5837 content: {
5838 "application/json": components["schemas"]["Error"];
5839 };
5840 };
5841 };
5842 };
5843 put?: never;
5844 /**
5845 * Set/replace a provider's runtime key (admin only)
5846 * @description Proxies the gateway's set-key path. The gateway encrypts the
5847 * plaintext key, persists it to gateway.yaml, and hot-applies the
5848 * rebuilt adapter — no restart. The backend forwards the JSON and
5849 * never returns the secret. 400 when the gateway master key is unset
5850 * (surfaced as ``validation_error``); 404 when the provider isn't a
5851 * configured entry.
5852 */
5853 post: {
5854 parameters: {
5855 query?: never;
5856 header?: never;
5857 path?: never;
5858 cookie?: never;
5859 };
5860 requestBody: {
5861 content: {
5862 "application/json": components["schemas"]["ProviderKeySetRequest"];
5863 };
5864 };
5865 responses: {
5866 /** @description Key applied; provider status returned (no secret) */
5867 200: {
5868 headers: {
5869 [name: string]: unknown;
5870 };
5871 content: {
5872 "application/json": components["schemas"]["ProviderKeyStatus"];
5873 };
5874 };
5875 /** @description Gateway master key is not set */
5876 400: {
5877 headers: {
5878 [name: string]: unknown;
5879 };
5880 content: {
5881 "application/json": components["schemas"]["Error"];
5882 };
5883 };
5884 /** @description Caller is not an admin */
5885 403: {
5886 headers: {
5887 [name: string]: unknown;
5888 };
5889 content: {
5890 "application/json": components["schemas"]["Error"];
5891 };
5892 };
5893 /** @description Provider not configured */
5894 404: {
5895 headers: {
5896 [name: string]: unknown;
5897 };
5898 content: {
5899 "application/json": components["schemas"]["Error"];
5900 };
5901 };
5902 };
5903 };
5904 delete?: never;
5905 options?: never;
5906 head?: never;
5907 patch?: never;
5908 trace?: never;
5909 };
5910 "/api/v1/admin/provider-keys/{provider}": {
5911 parameters: {
5912 query?: never;
5913 header?: never;
5914 path: {
5915 provider: string;
5916 };
5917 cookie?: never;
5918 };
5919 get?: never;
5920 put?: never;
5921 post?: never;
5922 /**
5923 * Revoke a provider's runtime key (admin only)
5924 * @description Proxies the gateway's revoke path. Only runtime
5925 * (encrypted-at-rest) keys can be revoked; an env-sourced key is
5926 * owned by the operator's environment and returns 409.
5927 */
5928 delete: {
5929 parameters: {
5930 query?: never;
5931 header?: never;
5932 path: {
5933 provider: string;
5934 };
5935 cookie?: never;
5936 };
5937 requestBody?: never;
5938 responses: {
5939 /** @description Runtime key revoked */
5940 204: {
5941 headers: {
5942 [name: string]: unknown;
5943 };
5944 content?: never;
5945 };
5946 /** @description Caller is not an admin */
5947 403: {
5948 headers: {
5949 [name: string]: unknown;
5950 };
5951 content: {
5952 "application/json": components["schemas"]["Error"];
5953 };
5954 };
5955 /** @description Provider not configured */
5956 404: {
5957 headers: {
5958 [name: string]: unknown;
5959 };
5960 content: {
5961 "application/json": components["schemas"]["Error"];
5962 };
5963 };
5964 /** @description Provider has no runtime key to revoke (e.g., env-sourced) */
5965 409: {
5966 headers: {
5967 [name: string]: unknown;
5968 };
5969 content: {
5970 "application/json": components["schemas"]["Error"];
5971 };
5972 };
5973 };
5974 };
5975 options?: never;
5976 head?: never;
5977 /**
5978 * Rotate a provider's runtime key (admin only)
5979 * @description Same mechanics as POST /api/v1/admin/provider-keys; the provider
5980 * comes from the path. Proxies the gateway, which retires the
5981 * displaced adapter and swaps the rebuilt one in. The backend never
5982 * returns the secret. 400 when the gateway master key is unset; 404
5983 * when the provider isn't configured.
5984 */
5985 patch: {
5986 parameters: {
5987 query?: never;
5988 header?: never;
5989 path: {
5990 provider: string;
5991 };
5992 cookie?: never;
5993 };
5994 requestBody: {
5995 content: {
5996 "application/json": components["schemas"]["ProviderKeyRotateRequest"];
5997 };
5998 };
5999 responses: {
6000 /** @description Key rotated; provider status returned (no secret) */
6001 200: {
6002 headers: {
6003 [name: string]: unknown;
6004 };
6005 content: {
6006 "application/json": components["schemas"]["ProviderKeyStatus"];
6007 };
6008 };
6009 /** @description Gateway master key is not set */
6010 400: {
6011 headers: {
6012 [name: string]: unknown;
6013 };
6014 content: {
6015 "application/json": components["schemas"]["Error"];
6016 };
6017 };
6018 /** @description Caller is not an admin */
6019 403: {
6020 headers: {
6021 [name: string]: unknown;
6022 };
6023 content: {
6024 "application/json": components["schemas"]["Error"];
6025 };
6026 };
6027 /** @description Provider not configured */
6028 404: {
6029 headers: {
6030 [name: string]: unknown;
6031 };
6032 content: {
6033 "application/json": components["schemas"]["Error"];
6034 };
6035 };
6036 };
6037 };
6038 trace?: never;
6039 };
6040 "/api/v1/admin/config": {
6041 parameters: {
6042 query?: never;
6043 header?: never;
6044 path?: never;
6045 cookie?: never;
6046 };
6047 /**
6048 * Sanitized live gateway config (admin only)
6049 * @description Proxies the gateway's ``/admin/v1/config`` endpoint. Used by
6050 * the web UI to populate the provider dropdown when editing
6051 * aliases. Secrets are not in the schema; the payload contains
6052 * env-var *names* only.
6053 */
6054 get: {
6055 parameters: {
6056 query?: never;
6057 header?: never;
6058 path?: never;
6059 cookie?: never;
6060 };
6061 requestBody?: never;
6062 responses: {
6063 /** @description Sanitized config payload */
6064 200: {
6065 headers: {
6066 [name: string]: unknown;
6067 };
6068 content: {
6069 "application/json": {
6070 [key: string]: unknown;
6071 };
6072 };
6073 };
6074 };
6075 };
6076 put?: never;
6077 post?: never;
6078 delete?: never;
6079 options?: never;
6080 head?: never;
6081 patch?: never;
6082 trace?: never;
6083 };
6084 "/api/v1/admin/users": {
6085 parameters: {
6086 query?: never;
6087 header?: never;
6088 path?: never;
6089 cookie?: never;
6090 };
6091 /**
6092 * List users for RBAC administration (Wave B v2 — PRD §5.2)
6093 * @description Admin-only. Returns the full list of non-deleted users with
6094 * their role + auth state. Supports filtering by role, email
6095 * substring search, and pagination. Default sort is email ASC.
6096 * Used by /lq-ai/admin/developer's role-management card.
6097 */
6098 get: {
6099 parameters: {
6100 query?: {
6101 role?: "admin" | "member" | "viewer";
6102 email_q?: string;
6103 limit?: number;
6104 offset?: number;
6105 };
6106 header?: never;
6107 path?: never;
6108 cookie?: never;
6109 };
6110 requestBody?: never;
6111 responses: {
6112 /** @description User list (paginated) */
6113 200: {
6114 headers: {
6115 [name: string]: unknown;
6116 };
6117 content: {
6118 "application/json": components["schemas"]["AdminUserListResponse"];
6119 };
6120 };
6121 /** @description Invalid role filter */
6122 400: {
6123 headers: {
6124 [name: string]: unknown;
6125 };
6126 content?: never;
6127 };
6128 /** @description Caller is not admin */
6129 403: {
6130 headers: {
6131 [name: string]: unknown;
6132 };
6133 content?: never;
6134 };
6135 };
6136 };
6137 put?: never;
6138 post?: never;
6139 delete?: never;
6140 options?: never;
6141 head?: never;
6142 patch?: never;
6143 trace?: never;
6144 };
6145 "/api/v1/admin/users/{user_id}/role": {
6146 parameters: {
6147 query?: never;
6148 header?: never;
6149 path: {
6150 user_id: string;
6151 };
6152 cookie?: never;
6153 };
6154 get?: never;
6155 put?: never;
6156 post?: never;
6157 delete?: never;
6158 options?: never;
6159 head?: never;
6160 /**
6161 * Set a user's RBAC role (admin | member | viewer)
6162 * @description Wave C. Updates ``users.role`` and keeps ``is_admin`` in sync
6163 * (True iff role='admin'). Idempotent: re-applying the same role
6164 * returns 200 without an audit row. Real changes write a
6165 * ``user.role_updated`` audit row with before/after values.
6166 *
6167 * Lockout protection: refuses to demote the last admin in the
6168 * deployment (409 — promote someone else first).
6169 */
6170 patch: {
6171 parameters: {
6172 query?: never;
6173 header?: never;
6174 path: {
6175 user_id: string;
6176 };
6177 cookie?: never;
6178 };
6179 requestBody: {
6180 content: {
6181 "application/json": {
6182 /** @enum {string} */
6183 role: "admin" | "member" | "viewer";
6184 };
6185 };
6186 };
6187 responses: {
6188 /** @description Updated role */
6189 200: {
6190 headers: {
6191 [name: string]: unknown;
6192 };
6193 content: {
6194 "application/json": {
6195 /** Format: uuid */
6196 user_id: string;
6197 /** Format: email */
6198 email: string;
6199 /** @enum {string} */
6200 role: "admin" | "member" | "viewer";
6201 is_admin: boolean;
6202 };
6203 };
6204 };
6205 /** @description Last-admin demotion lockout. */
6206 403: {
6207 headers: {
6208 [name: string]: unknown;
6209 };
6210 content: {
6211 "application/json": components["schemas"]["Error"];
6212 };
6213 };
6214 /** @description Target user not found. */
6215 404: {
6216 headers: {
6217 [name: string]: unknown;
6218 };
6219 content: {
6220 "application/json": components["schemas"]["Error"];
6221 };
6222 };
6223 /** @description Invalid role value. */
6224 422: {
6225 headers: {
6226 [name: string]: unknown;
6227 };
6228 content: {
6229 "application/json": components["schemas"]["Error"];
6230 };
6231 };
6232 };
6233 };
6234 trace?: never;
6235 };
6236 "/api/v1/admin/tier-policy": {
6237 parameters: {
6238 query?: never;
6239 header?: never;
6240 path?: never;
6241 cookie?: never;
6242 };
6243 /** Get current Inference Tier policy */
6244 get: {
6245 parameters: {
6246 query?: never;
6247 header?: never;
6248 path?: never;
6249 cookie?: never;
6250 };
6251 requestBody?: never;
6252 responses: {
6253 /** @description Policy */
6254 200: {
6255 headers: {
6256 [name: string]: unknown;
6257 };
6258 content: {
6259 "application/json": components["schemas"]["TierPolicy"];
6260 };
6261 };
6262 };
6263 };
6264 put?: never;
6265 post?: never;
6266 delete?: never;
6267 options?: never;
6268 head?: never;
6269 /**
6270 * Partial update to Inference Tier policy
6271 * @description Admin-only. Audited. Partial-update semantics — fields omitted from
6272 * the request body are left unchanged.
6273 */
6274 patch: {
6275 parameters: {
6276 query?: never;
6277 header?: never;
6278 path?: never;
6279 cookie?: never;
6280 };
6281 requestBody: {
6282 content: {
6283 "application/json": components["schemas"]["TierPolicy"];
6284 };
6285 };
6286 responses: {
6287 /** @description Updated */
6288 200: {
6289 headers: {
6290 [name: string]: unknown;
6291 };
6292 content: {
6293 "application/json": components["schemas"]["TierPolicy"];
6294 };
6295 };
6296 };
6297 };
6298 trace?: never;
6299 };
6300 "/api/v1/admin/usage": {
6301 parameters: {
6302 query?: never;
6303 header?: never;
6304 path?: never;
6305 cookie?: never;
6306 };
6307 /**
6308 * Cost + tokens aggregation across inference_routing_log
6309 * @description Admin-only. Aggregates ``inference_routing_log`` rows by one of
6310 * user | provider | model | tier | day. Refusals are excluded by
6311 * default (they didn't consume upstream tokens). Filters: date
6312 * range + the same grouping dimensions. Returns per-group rows
6313 * plus deployment-wide totals so the admin UI can render
6314 * percentages without a second query.
6315 */
6316 get: {
6317 parameters: {
6318 query?: {
6319 group_by?: "user" | "provider" | "model" | "tier" | "day";
6320 date_from?: string;
6321 date_to?: string;
6322 user_id?: string;
6323 provider?: string;
6324 model?: string;
6325 tier?: number;
6326 };
6327 header?: never;
6328 path?: never;
6329 cookie?: never;
6330 };
6331 requestBody?: never;
6332 responses: {
6333 /** @description Aggregated usage rows + totals */
6334 200: {
6335 headers: {
6336 [name: string]: unknown;
6337 };
6338 content: {
6339 "application/json": components["schemas"]["UsageResponse"];
6340 };
6341 };
6342 };
6343 };
6344 put?: never;
6345 post?: never;
6346 delete?: never;
6347 options?: never;
6348 head?: never;
6349 patch?: never;
6350 trace?: never;
6351 };
6352 "/api/v1/admin/word-addin/manifest": {
6353 parameters: {
6354 query?: never;
6355 header?: never;
6356 path?: never;
6357 cookie?: never;
6358 };
6359 /**
6360 * Render the Word add-in manifest XML for sideload (M3-B1)
6361 * @description Admin-only. Renders the Office Add-in XML manifest with the
6362 * operator's deployment URL + a freshly generated GUID substituted
6363 * into the template. Operators use the rendered file to sideload
6364 * the add-in via Microsoft 365 Admin Center.
6365 *
6366 * Origin resolution order:
6367 * 1. ``deployment_origin`` query param when supplied
6368 * 2. ``X-Forwarded-Proto`` + ``X-Forwarded-Host`` headers (the
6369 * operator's reverse-proxy reports these)
6370 * 3. The request URL's scheme + host (single-process dev fallback)
6371 *
6372 * Per PRD §9 DE-287, the Word add-in's user-facing feature tabs
6373 * (chat / skills / playbook execution / Inference Tier badge) are
6374 * descoped to M4 / community contribution; this M3-B1 endpoint
6375 * ships the install-and-authenticate plumbing.
6376 */
6377 get: {
6378 parameters: {
6379 query?: {
6380 /**
6381 * @description Override the deployment origin embedded in the manifest.
6382 * Defaults to the request's effective origin (reverse-proxy
6383 * aware). No trailing slash.
6384 */
6385 deployment_origin?: string;
6386 /**
6387 * @description Branded name surfaced inside Word's ribbon and the task
6388 * pane GetStarted message.
6389 */
6390 display_name?: string;
6391 /**
6392 * @description ProviderName value the manifest surfaces to Microsoft 365
6393 * Admin Center; typically the operator org's name.
6394 */
6395 provider_name?: string;
6396 };
6397 header?: never;
6398 path?: never;
6399 cookie?: never;
6400 };
6401 requestBody?: never;
6402 responses: {
6403 /** @description Rendered Office Add-in XML manifest */
6404 200: {
6405 headers: {
6406 /** @description Tells the browser to download the manifest as a file. */
6407 "Content-Disposition"?: string;
6408 [name: string]: unknown;
6409 };
6410 content: {
6411 "application/xml": string;
6412 };
6413 };
6414 /** @description Unauthenticated */
6415 401: {
6416 headers: {
6417 [name: string]: unknown;
6418 };
6419 content: {
6420 "application/json": components["schemas"]["Error"];
6421 };
6422 };
6423 /** @description Caller is not an admin user */
6424 403: {
6425 headers: {
6426 [name: string]: unknown;
6427 };
6428 content: {
6429 "application/json": components["schemas"]["Error"];
6430 };
6431 };
6432 };
6433 };
6434 put?: never;
6435 post?: never;
6436 delete?: never;
6437 options?: never;
6438 head?: never;
6439 patch?: never;
6440 trace?: never;
6441 };
6442 "/api/v1/word-addin/version": {
6443 parameters: {
6444 query?: never;
6445 header?: never;
6446 path?: never;
6447 cookie?: never;
6448 };
6449 /**
6450 * Word add-in version handshake (M3-B8)
6451 * @description **Unauthenticated.** The Word add-in's task pane calls this on
6452 * mount, BEFORE the user has signed in, so an out-of-date add-in
6453 * can surface an "Update needed" overlay rather than getting
6454 * stuck at a broken OAuth handshake or a breaking-change API
6455 * call.
6456 *
6457 * Response payload:
6458 * - `deployment_version` — the LQ.AI api package version (the
6459 * deployment's release number). Informational; the add-in
6460 * surfaces it in the "Update needed" overlay so a user can
6461 * quote it to support.
6462 * - `addin_min_compatible_version` / `addin_max_compatible_version`
6463 * — the semver range of add-in bundles this deployment can
6464 * talk to. The task pane refuses to render features outside
6465 * the range.
6466 * - `taskpane_bundle_url` — canonical URL of the task pane HTML
6467 * entry. The task pane already knows this from `window.location`
6468 * today; the field exists in the handshake so a future
6469 * deployment can serve the bundle from a CDN or operator-chosen
6470 * path without changing the manifest.
6471 * - `taskpane_bundle_hash` — optional SHA-256 of the deployed
6472 * bundle JS. M3-B8 ships this nullable; M3-B7 signing CI
6473 * populates the value from the build manifest. Null means
6474 * "don't enforce" — not an error.
6475 */
6476 get: {
6477 parameters: {
6478 query?: never;
6479 header?: never;
6480 path?: never;
6481 cookie?: never;
6482 };
6483 requestBody?: never;
6484 responses: {
6485 /** @description Version handshake payload */
6486 200: {
6487 headers: {
6488 [name: string]: unknown;
6489 };
6490 content: {
6491 "application/json": components["schemas"]["WordAddinVersionResponse"];
6492 };
6493 };
6494 };
6495 };
6496 put?: never;
6497 post?: never;
6498 delete?: never;
6499 options?: never;
6500 head?: never;
6501 patch?: never;
6502 trace?: never;
6503 };
6504 "/api/v1/inference/current-tier": {
6505 parameters: {
6506 query?: never;
6507 header?: never;
6508 path?: never;
6509 cookie?: never;
6510 };
6511 /**
6512 * Derive routed tier for a (provider, model) pair
6513 * @description The Tier Awareness UI's click-for-details panel calls this so
6514 * the user sees the human-readable tier label + the provider type
6515 * the Provider Compliance Matrix renders against. 404 when the
6516 * pair isn't in the gateway's model list.
6517 */
6518 get: {
6519 parameters: {
6520 query: {
6521 provider: string;
6522 model: string;
6523 };
6524 header?: never;
6525 path?: never;
6526 cookie?: never;
6527 };
6528 requestBody?: never;
6529 responses: {
6530 /** @description Current tier + explanation */
6531 200: {
6532 headers: {
6533 [name: string]: unknown;
6534 };
6535 content: {
6536 "application/json": components["schemas"]["CurrentTierResponse"];
6537 };
6538 };
6539 /** @description No (provider, model) entry in the gateway's model list. */
6540 404: {
6541 headers: {
6542 [name: string]: unknown;
6543 };
6544 content: {
6545 "application/json": components["schemas"]["Error"];
6546 };
6547 };
6548 };
6549 };
6550 put?: never;
6551 post?: never;
6552 delete?: never;
6553 options?: never;
6554 head?: never;
6555 patch?: never;
6556 trace?: never;
6557 };
6558 "/api/v1/inference/tier-config": {
6559 parameters: {
6560 query?: never;
6561 header?: never;
6562 path?: never;
6563 cookie?: never;
6564 };
6565 /**
6566 * Operator's tier policy (deployment-level disclosure)
6567 * @description User-accessible read of allowed_tiers_global + the default /
6568 * privileged minima. The admin write surface lives at
6569 * ``PATCH /api/v1/admin/tier-policy``.
6570 */
6571 get: {
6572 parameters: {
6573 query?: never;
6574 header?: never;
6575 path?: never;
6576 cookie?: never;
6577 };
6578 requestBody?: never;
6579 responses: {
6580 /** @description Tier policy snapshot */
6581 200: {
6582 headers: {
6583 [name: string]: unknown;
6584 };
6585 content: {
6586 "application/json": components["schemas"]["TierConfigResponse"];
6587 };
6588 };
6589 };
6590 };
6591 put?: never;
6592 post?: never;
6593 delete?: never;
6594 options?: never;
6595 head?: never;
6596 patch?: never;
6597 trace?: never;
6598 };
6599 "/api/v1/inference/override-tier-floor": {
6600 parameters: {
6601 query?: never;
6602 header?: never;
6603 path?: never;
6604 cookie?: never;
6605 };
6606 get?: never;
6607 put?: never;
6608 /**
6609 * Re-run a refused inference with the tier floor lifted (admin only)
6610 * @description Wave D.1 T4. Admin-only override that re-runs the original user
6611 * prompt with ``tier_floor=None`` for this turn. Looks up the
6612 * ``kind='refusal'`` message at ``message_id``, finds the
6613 * immediately preceding ``kind='user'`` message in the same chat,
6614 * and forwards both to the gateway with no project floor and no
6615 * per-call minimum. Persists a new ``kind='ai'`` ``Message`` row
6616 * and writes an ``audit_log`` row with the operator-supplied
6617 * ``reason``. Returns the new message + the routing-log row id
6618 * the gateway wrote.
6619 *
6620 * M1 binds to the ``is_admin`` role. Per-user
6621 * ``override_tier_floor`` capability is deferred to v1.1+.
6622 */
6623 post: {
6624 parameters: {
6625 query?: never;
6626 header?: never;
6627 path?: never;
6628 cookie?: never;
6629 };
6630 requestBody: {
6631 content: {
6632 "application/json": {
6633 /** Format: uuid */
6634 message_id: string;
6635 reason: string;
6636 };
6637 };
6638 };
6639 responses: {
6640 /** @description Re-run completed; new ``kind='ai'`` message persisted. */
6641 200: {
6642 headers: {
6643 [name: string]: unknown;
6644 };
6645 content: {
6646 "application/json": {
6647 ai_message: components["schemas"]["Message"];
6648 /** Format: uuid */
6649 routing_log_id?: string | null;
6650 };
6651 };
6652 };
6653 /** @description Caller is not an admin. */
6654 403: {
6655 headers: {
6656 [name: string]: unknown;
6657 };
6658 content: {
6659 "application/json": components["schemas"]["Error"];
6660 };
6661 };
6662 /** @description ``message_id`` does not resolve to a refusal row. */
6663 404: {
6664 headers: {
6665 [name: string]: unknown;
6666 };
6667 content: {
6668 "application/json": components["schemas"]["Error"];
6669 };
6670 };
6671 };
6672 };
6673 delete?: never;
6674 options?: never;
6675 head?: never;
6676 patch?: never;
6677 trace?: never;
6678 };
6679 "/api/v1/chats/{chat_id}/receipts": {
6680 parameters: {
6681 query?: never;
6682 header?: never;
6683 path?: never;
6684 cookie?: never;
6685 };
6686 /**
6687 * Chronological event log for a chat (replay-at-read)
6688 * @description Wave D.1 T5 (spec §7.6). Merges chronological events from four
6689 * source tables into a single timestamp-ordered stream:
6690 *
6691 * * ``messages`` (``kind='message'``)
6692 * * ``messages.applied_skills`` (one event per skill name; ``kind='skill'``)
6693 * * ``inference_routing_log`` (``kind='inference'`` or ``kind='error'`` if ``refused=True``)
6694 * * ``audit_log`` (``kind='audit'`` or ``kind='retrieval'`` if ``action='inference.kb_chunks_retrieved'``)
6695 *
6696 * Owner-of-chat or admin only. Replay-at-read for M1 — chats are
6697 * bounded (<100 events typical). A materialized ``chat_receipts``
6698 * projection is a v1.1+ candidate if latency degrades.
6699 */
6700 get: {
6701 parameters: {
6702 query?: {
6703 /**
6704 * @description Comma-separated subset of: ``message``, ``inference``,
6705 * ``audit``, ``skill``, ``retrieval``, ``error``. Omit for
6706 * all kinds. Unknown tokens are silently ignored.
6707 */
6708 event_kinds?: string;
6709 };
6710 header?: never;
6711 path: {
6712 chat_id: string;
6713 };
6714 cookie?: never;
6715 };
6716 requestBody?: never;
6717 responses: {
6718 /** @description Chronological list of receipt events, oldest first. */
6719 200: {
6720 headers: {
6721 [name: string]: unknown;
6722 };
6723 content: {
6724 "application/json": {
6725 /** Format: date-time */
6726 ts: string;
6727 /** @enum {string} */
6728 kind: "message" | "inference" | "audit" | "skill" | "retrieval" | "error";
6729 detail: {
6730 [key: string]: unknown;
6731 };
6732 }[];
6733 };
6734 };
6735 /** @description Caller is not the chat owner or an admin. */
6736 403: {
6737 headers: {
6738 [name: string]: unknown;
6739 };
6740 content: {
6741 "application/json": components["schemas"]["Error"];
6742 };
6743 };
6744 /** @description Chat not found. */
6745 404: {
6746 headers: {
6747 [name: string]: unknown;
6748 };
6749 content: {
6750 "application/json": components["schemas"]["Error"];
6751 };
6752 };
6753 };
6754 };
6755 put?: never;
6756 post?: never;
6757 delete?: never;
6758 options?: never;
6759 head?: never;
6760 patch?: never;
6761 trace?: never;
6762 };
6763 "/api/v1/chats/{chat_id}/receipts/export.jsonl": {
6764 parameters: {
6765 query?: never;
6766 header?: never;
6767 path?: never;
6768 cookie?: never;
6769 };
6770 /** Export receipts as JSONL (one event per line) */
6771 get: {
6772 parameters: {
6773 query?: {
6774 /** @description Comma-separated subset (same as the JSON endpoint) */
6775 event_kinds?: string;
6776 };
6777 header?: never;
6778 path: {
6779 chat_id: string;
6780 };
6781 cookie?: never;
6782 };
6783 requestBody?: never;
6784 responses: {
6785 /** @description JSONL stream — one event per line */
6786 200: {
6787 headers: {
6788 [name: string]: unknown;
6789 };
6790 content: {
6791 "application/jsonl": string;
6792 };
6793 };
6794 /** @description Forbidden — not the owner or admin */
6795 403: {
6796 headers: {
6797 [name: string]: unknown;
6798 };
6799 content?: never;
6800 };
6801 /** @description Chat not found */
6802 404: {
6803 headers: {
6804 [name: string]: unknown;
6805 };
6806 content?: never;
6807 };
6808 };
6809 };
6810 put?: never;
6811 post?: never;
6812 delete?: never;
6813 options?: never;
6814 head?: never;
6815 patch?: never;
6816 trace?: never;
6817 };
6818 "/api/v1/chats/{chat_id}/tool-calls/{pending_call_id}": {
6819 parameters: {
6820 query?: never;
6821 header?: never;
6822 path?: never;
6823 cookie?: never;
6824 };
6825 get?: never;
6826 put?: never;
6827 /** Approve or deny a pending destructive chat tool-call; resumes the turn */
6828 post: {
6829 parameters: {
6830 query?: never;
6831 header?: never;
6832 path: {
6833 chat_id: string;
6834 pending_call_id: string;
6835 };
6836 cookie?: never;
6837 };
6838 requestBody: {
6839 content: {
6840 "application/json": components["schemas"]["ToolCallDecisionRequest"];
6841 };
6842 };
6843 responses: {
6844 /** @description SSE stream — resumes the turn after approval or denial */
6845 200: {
6846 headers: {
6847 [name: string]: unknown;
6848 };
6849 content: {
6850 "text/event-stream": string;
6851 };
6852 };
6853 /** @description Malformed request body */
6854 400: {
6855 headers: {
6856 [name: string]: unknown;
6857 };
6858 content?: never;
6859 };
6860 /** @description Chat or pending tool-call not found (id-probing-safe) */
6861 404: {
6862 headers: {
6863 [name: string]: unknown;
6864 };
6865 content?: never;
6866 };
6867 /** @description Tool-call already resolved or confirmation expired */
6868 409: {
6869 headers: {
6870 [name: string]: unknown;
6871 };
6872 content?: never;
6873 };
6874 };
6875 };
6876 delete?: never;
6877 options?: never;
6878 head?: never;
6879 patch?: never;
6880 trace?: never;
6881 };
6882 "/api/v1/integrations/slack/workspaces": {
6883 parameters: {
6884 query?: never;
6885 header?: never;
6886 path?: never;
6887 cookie?: never;
6888 };
6889 get?: never;
6890 put?: never;
6891 /**
6892 * Persist a Slack workspace from the slack-bridge OAuth flow (M3-D1)
6893 * @description Service-to-service endpoint. Authenticated by a shared
6894 * `Authorization: Bearer ${LQ_AI_BRIDGE_TOKEN}` token (NOT a user
6895 * JWT) — the slack-bridge is the only intended caller.
6896 *
6897 * The bridge POSTs the workspace tuple after the operator
6898 * completes the Slack OAuth install flow at
6899 * `${LQ_AI_BRIDGE_PUBLIC_URL}/slack/oauth/install`. The api
6900 * encrypts the bot token at rest under `LQ_AI_BRIDGE_MASTER_KEY`
6901 * (a separate Fernet master key from the gateway's
6902 * `LQ_AI_GATEWAY_MASTER_KEY` — different threat models) and
6903 * upserts on `team_id` so a re-install (Slack rotates bot tokens
6904 * on re-install) replaces the old ciphertext + scope + installer
6905 * in place. Soft-deleted rows revive on re-install.
6906 *
6907 * 500 (not 401) is the response when the operator hasn't set
6908 * `LQ_AI_BRIDGE_TOKEN` on the api — accepting bridge traffic
6909 * with no enforced secret would silently break the trust
6910 * contract.
6911 */
6912 post: {
6913 parameters: {
6914 query?: never;
6915 header?: never;
6916 path?: never;
6917 cookie?: never;
6918 };
6919 requestBody: {
6920 content: {
6921 "application/json": components["schemas"]["SlackWorkspaceCreate"];
6922 };
6923 };
6924 responses: {
6925 /** @description Persisted (or upserted) the workspace record */
6926 201: {
6927 headers: {
6928 [name: string]: unknown;
6929 };
6930 content: {
6931 "application/json": components["schemas"]["SlackWorkspaceResponse"];
6932 };
6933 };
6934 /** @description Missing, malformed, or non-matching bridge bearer token */
6935 401: {
6936 headers: {
6937 [name: string]: unknown;
6938 };
6939 content?: never;
6940 };
6941 /** @description Operator has not configured `LQ_AI_BRIDGE_TOKEN` on the api */
6942 500: {
6943 headers: {
6944 [name: string]: unknown;
6945 };
6946 content?: never;
6947 };
6948 };
6949 };
6950 delete?: never;
6951 options?: never;
6952 head?: never;
6953 patch?: never;
6954 trace?: never;
6955 };
6956 "/api/v1/integrations/teams/tenants": {
6957 parameters: {
6958 query?: never;
6959 header?: never;
6960 path?: never;
6961 cookie?: never;
6962 };
6963 get?: never;
6964 put?: never;
6965 /**
6966 * Persist a Microsoft 365 tenant from the teams-bridge OAuth flow (M3-D3)
6967 * @description Service-to-service endpoint. Authenticated by the **same**
6968 * `Authorization: Bearer ${LQ_AI_BRIDGE_TOKEN}` bearer as the
6969 * slack-bridge endpoint per M3-D3 decision #2 — one shared
6970 * secret authenticates every bridge → api call.
6971 *
6972 * Unlike the Slack equivalent, no bot token is persisted here:
6973 * Microsoft Teams uses operator-supplied APP-LEVEL bot
6974 * credentials (one `MICROSOFT_APP_ID` per deployment) not
6975 * per-tenant tokens. The persisted record carries only the
6976 * tenant id + display name + installer object id.
6977 *
6978 * Upserts on `tenant_id`. Soft-deleted rows revive on
6979 * re-install. `installed_at` is NOT moved by upsert (operators
6980 * can infer re-install activity from other field changes).
6981 */
6982 post: {
6983 parameters: {
6984 query?: never;
6985 header?: never;
6986 path?: never;
6987 cookie?: never;
6988 };
6989 requestBody: {
6990 content: {
6991 "application/json": components["schemas"]["TeamsTenantCreate"];
6992 };
6993 };
6994 responses: {
6995 /** @description Persisted (or upserted) the tenant record */
6996 201: {
6997 headers: {
6998 [name: string]: unknown;
6999 };
7000 content: {
7001 "application/json": components["schemas"]["TeamsTenantResponse"];
7002 };
7003 };
7004 /** @description Missing, malformed, or non-matching bridge bearer token */
7005 401: {
7006 headers: {
7007 [name: string]: unknown;
7008 };
7009 content?: never;
7010 };
7011 /** @description Operator has not configured `LQ_AI_BRIDGE_TOKEN` on the api */
7012 500: {
7013 headers: {
7014 [name: string]: unknown;
7015 };
7016 content?: never;
7017 };
7018 };
7019 };
7020 delete?: never;
7021 options?: never;
7022 head?: never;
7023 patch?: never;
7024 trace?: never;
7025 };
7026 "/api/v1/admin/intake-bridges": {
7027 parameters: {
7028 query?: never;
7029 header?: never;
7030 path?: never;
7031 cookie?: never;
7032 };
7033 /**
7034 * List live Slack + Teams installs for the admin UI (M3-D4)
7035 * @description Returns non-soft-deleted Slack workspaces and Teams tenants,
7036 * sorted by `installed_at DESC` within each section. Admin-only.
7037 * Backs the SvelteKit admin page at `/lq-ai/admin/intake-bridges`.
7038 */
7039 get: {
7040 parameters: {
7041 query?: never;
7042 header?: never;
7043 path?: never;
7044 cookie?: never;
7045 };
7046 requestBody?: never;
7047 responses: {
7048 /** @description Live install list */
7049 200: {
7050 headers: {
7051 [name: string]: unknown;
7052 };
7053 content: {
7054 "application/json": components["schemas"]["IntakeBridgesList"];
7055 };
7056 };
7057 /** @description Not authenticated */
7058 401: {
7059 headers: {
7060 [name: string]: unknown;
7061 };
7062 content?: never;
7063 };
7064 /** @description Authenticated but not an admin */
7065 403: {
7066 headers: {
7067 [name: string]: unknown;
7068 };
7069 content?: never;
7070 };
7071 };
7072 };
7073 put?: never;
7074 post?: never;
7075 delete?: never;
7076 options?: never;
7077 head?: never;
7078 patch?: never;
7079 trace?: never;
7080 };
7081 "/api/v1/admin/intake-bridges/slack/{workspace_id}": {
7082 parameters: {
7083 query?: never;
7084 header?: never;
7085 path?: never;
7086 cookie?: never;
7087 };
7088 get?: never;
7089 put?: never;
7090 post?: never;
7091 /**
7092 * Soft-delete a Slack workspace install (M3-D4)
7093 * @description Sets `deleted_at` to now. The row stays in the DB so a
7094 * re-install via the slack-bridge OAuth flow revives it in
7095 * place per the M3-D1 upsert semantics; the install history
7096 * is preserved across disconnect/reconnect cycles.
7097 */
7098 delete: {
7099 parameters: {
7100 query?: never;
7101 header?: never;
7102 path: {
7103 workspace_id: string;
7104 };
7105 cookie?: never;
7106 };
7107 requestBody?: never;
7108 responses: {
7109 /** @description Soft-deleted */
7110 204: {
7111 headers: {
7112 [name: string]: unknown;
7113 };
7114 content?: never;
7115 };
7116 /** @description Not authenticated */
7117 401: {
7118 headers: {
7119 [name: string]: unknown;
7120 };
7121 content?: never;
7122 };
7123 /** @description Authenticated but not an admin */
7124 403: {
7125 headers: {
7126 [name: string]: unknown;
7127 };
7128 content?: never;
7129 };
7130 /** @description Workspace not found or already disconnected */
7131 404: {
7132 headers: {
7133 [name: string]: unknown;
7134 };
7135 content?: never;
7136 };
7137 };
7138 };
7139 options?: never;
7140 head?: never;
7141 patch?: never;
7142 trace?: never;
7143 };
7144 "/api/v1/admin/intake-bridges/teams/{tenant_id}": {
7145 parameters: {
7146 query?: never;
7147 header?: never;
7148 path?: never;
7149 cookie?: never;
7150 };
7151 get?: never;
7152 put?: never;
7153 post?: never;
7154 /**
7155 * Soft-delete a Microsoft 365 tenant install (M3-D4)
7156 * @description Same posture as the Slack endpoint above — soft-delete with
7157 * revivable row.
7158 */
7159 delete: {
7160 parameters: {
7161 query?: never;
7162 header?: never;
7163 path: {
7164 tenant_id: string;
7165 };
7166 cookie?: never;
7167 };
7168 requestBody?: never;
7169 responses: {
7170 /** @description Soft-deleted */
7171 204: {
7172 headers: {
7173 [name: string]: unknown;
7174 };
7175 content?: never;
7176 };
7177 /** @description Not authenticated */
7178 401: {
7179 headers: {
7180 [name: string]: unknown;
7181 };
7182 content?: never;
7183 };
7184 /** @description Authenticated but not an admin */
7185 403: {
7186 headers: {
7187 [name: string]: unknown;
7188 };
7189 content?: never;
7190 };
7191 /** @description Tenant not found or already disconnected */
7192 404: {
7193 headers: {
7194 [name: string]: unknown;
7195 };
7196 content?: never;
7197 };
7198 };
7199 };
7200 options?: never;
7201 head?: never;
7202 patch?: never;
7203 trace?: never;
7204 };
7205 "/api/v1/autonomous/sessions": {
7206 parameters: {
7207 query?: never;
7208 header?: never;
7209 path?: never;
7210 cookie?: never;
7211 };
7212 /**
7213 * List the calling user's autonomous sessions (newest first, paginated)
7214 * @description Returns the caller's sessions ordered by ``created_at DESC``.
7215 * ``limit`` is clamped to [1, 200]; ``offset`` to [0, ∞).
7216 * Only the caller's own sessions are returned — cross-user isolation
7217 * is enforced at the query level.
7218 */
7219 get: {
7220 parameters: {
7221 query?: {
7222 /** @description Maximum number of sessions to return (clamped to [1, 200]). */
7223 limit?: number;
7224 /** @description Zero-based index of the first result to return. */
7225 offset?: number;
7226 };
7227 header?: never;
7228 path?: never;
7229 cookie?: never;
7230 };
7231 requestBody?: never;
7232 responses: {
7233 /** @description Paginated list of autonomous sessions */
7234 200: {
7235 headers: {
7236 [name: string]: unknown;
7237 };
7238 content: {
7239 "application/json": components["schemas"]["AutonomousSessionListResponse"];
7240 };
7241 };
7242 /** @description Not authenticated */
7243 401: {
7244 headers: {
7245 [name: string]: unknown;
7246 };
7247 content?: never;
7248 };
7249 };
7250 };
7251 put?: never;
7252 post?: never;
7253 delete?: never;
7254 options?: never;
7255 head?: never;
7256 patch?: never;
7257 trace?: never;
7258 };
7259 "/api/v1/autonomous/sessions/{session_id}": {
7260 parameters: {
7261 query?: never;
7262 header?: never;
7263 path?: never;
7264 cookie?: never;
7265 };
7266 /**
7267 * Fetch a single autonomous session with its full receipt
7268 * @description Returns the session plus a live-reconstructed receipt built from
7269 * audit rows (works for running and completed sessions). A completed
7270 * session also has the receipt persisted in ``result``.
7271 *
7272 * Another user's ``session_id`` returns 404 (not 403) to avoid
7273 * existence disclosure.
7274 */
7275 get: {
7276 parameters: {
7277 query?: never;
7278 header?: never;
7279 path: {
7280 session_id: string;
7281 };
7282 cookie?: never;
7283 };
7284 requestBody?: never;
7285 responses: {
7286 /** @description Session detail with receipt */
7287 200: {
7288 headers: {
7289 [name: string]: unknown;
7290 };
7291 content: {
7292 "application/json": components["schemas"]["AutonomousSessionDetailResponse"];
7293 };
7294 };
7295 /** @description Not authenticated */
7296 401: {
7297 headers: {
7298 [name: string]: unknown;
7299 };
7300 content?: never;
7301 };
7302 /** @description Session not found */
7303 404: {
7304 headers: {
7305 [name: string]: unknown;
7306 };
7307 content?: never;
7308 };
7309 };
7310 };
7311 put?: never;
7312 post?: never;
7313 delete?: never;
7314 options?: never;
7315 head?: never;
7316 patch?: never;
7317 trace?: never;
7318 };
7319 "/api/v1/autonomous/sessions/{session_id}/findings": {
7320 parameters: {
7321 query?: never;
7322 header?: never;
7323 path?: never;
7324 cookie?: never;
7325 };
7326 /**
7327 * List a session's persisted findings (work-product, stable order)
7328 * @description Returns the run's persisted findings (the ``emit_finding`` chokepoint
7329 * work-product) ordered by ``created_at ASC, id ASC``. Rows a run
7330 * emits in its single executor commit typically share one
7331 * ``created_at`` (transaction-stable ``now()``), so ``id`` is the
7332 * deterministic tiebreaker that keeps pagination stable — a
7333 * repeatable order, not a guaranteed emission sequence. This differs
7334 * intentionally from the newest-first autonomous lists: these are one
7335 * run's output.
7336 *
7337 * Owner-gated by loading the owned session first (the findings table
7338 * has no ``user_id`` — authz is via the parent session). Another
7339 * user's ``session_id`` — or a missing one — returns 404 (not 403) to
7340 * avoid existence disclosure. ``limit`` is clamped to [1, 200];
7341 * ``offset`` to [0, ∞).
7342 */
7343 get: {
7344 parameters: {
7345 query?: {
7346 /** @description Maximum number of findings to return (clamped to [1, 200]). */
7347 limit?: number;
7348 /** @description Zero-based index of the first result to return. */
7349 offset?: number;
7350 };
7351 header?: never;
7352 path: {
7353 session_id: string;
7354 };
7355 cookie?: never;
7356 };
7357 requestBody?: never;
7358 responses: {
7359 /** @description Paginated list of the session's findings (stable created_at, id order) */
7360 200: {
7361 headers: {
7362 [name: string]: unknown;
7363 };
7364 content: {
7365 "application/json": components["schemas"]["AutonomousFindingListResponse"];
7366 };
7367 };
7368 /** @description Not authenticated */
7369 401: {
7370 headers: {
7371 [name: string]: unknown;
7372 };
7373 content?: never;
7374 };
7375 /** @description Session not found */
7376 404: {
7377 headers: {
7378 [name: string]: unknown;
7379 };
7380 content?: never;
7381 };
7382 };
7383 };
7384 put?: never;
7385 post?: never;
7386 delete?: never;
7387 options?: never;
7388 head?: never;
7389 patch?: never;
7390 trace?: never;
7391 };
7392 "/api/v1/autonomous/sessions/{session_id}/artifacts": {
7393 parameters: {
7394 query?: never;
7395 header?: never;
7396 path?: never;
7397 cookie?: never;
7398 };
7399 /**
7400 * List a session's persisted document-grade artifacts (work-product, stable order)
7401 * @description Returns the run's persisted artifact references (the
7402 * ``emit_artifact`` chokepoint work-product — markdown memos an
7403 * opted-in run saved into its target knowledge base as real
7404 * documents) ordered by ``created_at ASC, id ASC`` — one run's rows
7405 * typically share ``created_at`` (transaction-stable ``now()``), so
7406 * ``id`` is the deterministic tiebreaker that keeps pagination
7407 * stable; a repeatable order, not a guaranteed emission sequence.
7408 * Mirrors the findings read above.
7409 *
7410 * Owner-gated by loading the owned session first (the artifacts
7411 * table has no ``user_id`` — authz is via the parent session).
7412 * Another user's ``session_id`` — or a missing one — returns 404
7413 * (not 403) to avoid existence disclosure. ``limit`` is clamped to
7414 * [1, 200]; ``offset`` to [0, ∞).
7415 *
7416 * ``document_id`` is enriched at read time via the unique
7417 * ``documents.file_id``. Deletion semantics: a hard file-delete
7418 * SET-NULLs ``file_id`` (name/size metadata survives; both refs
7419 * return null); deleting the session removes these reference rows
7420 * but never the KB document — the document outlives the session.
7421 */
7422 get: {
7423 parameters: {
7424 query?: {
7425 /** @description Maximum number of artifacts to return (clamped to [1, 200]). */
7426 limit?: number;
7427 /** @description Zero-based index of the first result to return. */
7428 offset?: number;
7429 };
7430 header?: never;
7431 path: {
7432 session_id: string;
7433 };
7434 cookie?: never;
7435 };
7436 requestBody?: never;
7437 responses: {
7438 /** @description Paginated list of the session's artifact references (stable created_at, id order) */
7439 200: {
7440 headers: {
7441 [name: string]: unknown;
7442 };
7443 content: {
7444 "application/json": components["schemas"]["AutonomousArtifactListResponse"];
7445 };
7446 };
7447 /** @description Not authenticated */
7448 401: {
7449 headers: {
7450 [name: string]: unknown;
7451 };
7452 content?: never;
7453 };
7454 /** @description Session not found */
7455 404: {
7456 headers: {
7457 [name: string]: unknown;
7458 };
7459 content?: never;
7460 };
7461 };
7462 };
7463 put?: never;
7464 post?: never;
7465 delete?: never;
7466 options?: never;
7467 head?: never;
7468 patch?: never;
7469 trace?: never;
7470 };
7471 "/api/v1/autonomous/sessions/{session_id}/halt": {
7472 parameters: {
7473 query?: never;
7474 header?: never;
7475 path?: never;
7476 cookie?: never;
7477 };
7478 get?: never;
7479 put?: never;
7480 /**
7481 * Request an immediate halt for an autonomous session (idempotent)
7482 * @description Sets ``halt_state = 'halt_requested'`` so the executor's R5 temporal
7483 * brake trips on the next tool call and transitions the session to
7484 * ``halted``.
7485 *
7486 * **Idempotent:** if ``halt_state`` is already ``halt_requested`` or
7487 * ``halted``, the endpoint returns the current session state with 200
7488 * and writes no duplicate audit row.
7489 *
7490 * Another user's ``session_id`` returns 404 (not 403).
7491 */
7492 post: {
7493 parameters: {
7494 query?: never;
7495 header?: never;
7496 path: {
7497 session_id: string;
7498 };
7499 cookie?: never;
7500 };
7501 requestBody?: {
7502 content: {
7503 "*/*"?: never;
7504 };
7505 };
7506 responses: {
7507 /** @description Updated session (halt requested or already halted) */
7508 200: {
7509 headers: {
7510 [name: string]: unknown;
7511 };
7512 content: {
7513 "application/json": components["schemas"]["AutonomousSessionRead"];
7514 };
7515 };
7516 /** @description Not authenticated */
7517 401: {
7518 headers: {
7519 [name: string]: unknown;
7520 };
7521 content?: never;
7522 };
7523 /** @description Session not found */
7524 404: {
7525 headers: {
7526 [name: string]: unknown;
7527 };
7528 content?: never;
7529 };
7530 };
7531 };
7532 delete?: never;
7533 options?: never;
7534 head?: never;
7535 patch?: never;
7536 trace?: never;
7537 };
7538 "/api/v1/autonomous/memory": {
7539 parameters: {
7540 query?: never;
7541 header?: never;
7542 path?: never;
7543 cookie?: never;
7544 };
7545 /**
7546 * List the calling user's autonomous memory entries (non-deleted, newest first)
7547 * @description Returns the caller's non-deleted memory entries ordered by
7548 * ``created_at DESC``. Pass ``?state=proposed|kept|dismissed`` to
7549 * filter by review state; omitting ``state`` returns all non-deleted
7550 * entries. ``limit`` is clamped to [1, 200]; ``offset`` to [0, ∞).
7551 */
7552 get: {
7553 parameters: {
7554 query?: {
7555 /** @description Filter by review state; omit to return all non-deleted entries. */
7556 state?: "proposed" | "kept" | "dismissed";
7557 /** @description Narrow to the memories a specific run proposed; omit for all. */
7558 source_session_id?: string;
7559 /** @description Maximum number of entries to return (clamped to [1, 200]). */
7560 limit?: number;
7561 /** @description Zero-based index of the first result to return. */
7562 offset?: number;
7563 };
7564 header?: never;
7565 path?: never;
7566 cookie?: never;
7567 };
7568 requestBody?: never;
7569 responses: {
7570 /** @description Paginated list of autonomous memory entries */
7571 200: {
7572 headers: {
7573 [name: string]: unknown;
7574 };
7575 content: {
7576 "application/json": components["schemas"]["AutonomousMemoryListResponse"];
7577 };
7578 };
7579 /** @description Not authenticated */
7580 401: {
7581 headers: {
7582 [name: string]: unknown;
7583 };
7584 content?: never;
7585 };
7586 };
7587 };
7588 put?: never;
7589 post?: never;
7590 delete?: never;
7591 options?: never;
7592 head?: never;
7593 patch?: never;
7594 trace?: never;
7595 };
7596 "/api/v1/autonomous/memory/{memory_id}/keep": {
7597 parameters: {
7598 query?: never;
7599 header?: never;
7600 path?: never;
7601 cookie?: never;
7602 };
7603 get?: never;
7604 put?: never;
7605 /**
7606 * Keep (approve) an autonomous memory entry; optional edit-on-keep
7607 * @description Transitions ``proposed`` or ``dismissed`` → ``kept``. If the
7608 * optional body supplies ``content``, the entry's text is overwritten
7609 * (edit-on-keep).
7610 *
7611 * **Re-keep semantics:** if the entry is already ``kept``, the action
7612 * is allowed — content is updated if provided; ``kept_at`` is
7613 * preserved.
7614 *
7615 * Another user's ``memory_id`` returns 404. Audited.
7616 */
7617 post: {
7618 parameters: {
7619 query?: never;
7620 header?: never;
7621 path: {
7622 memory_id: string;
7623 };
7624 cookie?: never;
7625 };
7626 requestBody?: {
7627 content: {
7628 "application/json": components["schemas"]["MemoryKeepRequest"];
7629 };
7630 };
7631 responses: {
7632 /** @description Updated memory entry (now kept) */
7633 200: {
7634 headers: {
7635 [name: string]: unknown;
7636 };
7637 content: {
7638 "application/json": components["schemas"]["AutonomousMemoryRead"];
7639 };
7640 };
7641 /** @description Not authenticated */
7642 401: {
7643 headers: {
7644 [name: string]: unknown;
7645 };
7646 content?: never;
7647 };
7648 /** @description Memory entry not found */
7649 404: {
7650 headers: {
7651 [name: string]: unknown;
7652 };
7653 content?: never;
7654 };
7655 };
7656 };
7657 delete?: never;
7658 options?: never;
7659 head?: never;
7660 patch?: never;
7661 trace?: never;
7662 };
7663 "/api/v1/autonomous/memory/{memory_id}/dismiss": {
7664 parameters: {
7665 query?: never;
7666 header?: never;
7667 path?: never;
7668 cookie?: never;
7669 };
7670 get?: never;
7671 put?: never;
7672 /**
7673 * Dismiss an autonomous memory entry
7674 * @description Transitions ``proposed`` or ``kept`` → ``dismissed``.
7675 *
7676 * Another user's ``memory_id`` returns 404. Audited.
7677 */
7678 post: {
7679 parameters: {
7680 query?: never;
7681 header?: never;
7682 path: {
7683 memory_id: string;
7684 };
7685 cookie?: never;
7686 };
7687 requestBody?: never;
7688 responses: {
7689 /** @description Updated memory entry (now dismissed) */
7690 200: {
7691 headers: {
7692 [name: string]: unknown;
7693 };
7694 content: {
7695 "application/json": components["schemas"]["AutonomousMemoryRead"];
7696 };
7697 };
7698 /** @description Not authenticated */
7699 401: {
7700 headers: {
7701 [name: string]: unknown;
7702 };
7703 content?: never;
7704 };
7705 /** @description Memory entry not found */
7706 404: {
7707 headers: {
7708 [name: string]: unknown;
7709 };
7710 content?: never;
7711 };
7712 };
7713 };
7714 delete?: never;
7715 options?: never;
7716 head?: never;
7717 patch?: never;
7718 trace?: never;
7719 };
7720 "/api/v1/autonomous/memory/{memory_id}": {
7721 parameters: {
7722 query?: never;
7723 header?: never;
7724 path?: never;
7725 cookie?: never;
7726 };
7727 get?: never;
7728 put?: never;
7729 post?: never;
7730 /**
7731 * Soft-delete an autonomous memory entry (returns 200 with updated entry)
7732 * @description Soft-deletes the entry by setting ``deleted_at=now(UTC)``.
7733 * Returns **200** with the updated (deleted) entry — not 204 — to
7734 * avoid the FastAPI JSONResponse/204 assertion pitfall.
7735 *
7736 * A subsequent GET excludes the entry; keep/dismiss/delete on a
7737 * deleted entry return 404.
7738 *
7739 * Another user's ``memory_id`` returns 404. Audited.
7740 */
7741 delete: {
7742 parameters: {
7743 query?: never;
7744 header?: never;
7745 path: {
7746 memory_id: string;
7747 };
7748 cookie?: never;
7749 };
7750 requestBody?: never;
7751 responses: {
7752 /** @description Soft-deleted memory entry */
7753 200: {
7754 headers: {
7755 [name: string]: unknown;
7756 };
7757 content: {
7758 "application/json": components["schemas"]["AutonomousMemoryRead"];
7759 };
7760 };
7761 /** @description Not authenticated */
7762 401: {
7763 headers: {
7764 [name: string]: unknown;
7765 };
7766 content?: never;
7767 };
7768 /** @description Memory entry not found */
7769 404: {
7770 headers: {
7771 [name: string]: unknown;
7772 };
7773 content?: never;
7774 };
7775 };
7776 };
7777 options?: never;
7778 head?: never;
7779 patch?: never;
7780 trace?: never;
7781 };
7782 "/api/v1/autonomous/precedents": {
7783 parameters: {
7784 query?: never;
7785 header?: never;
7786 path?: never;
7787 cookie?: never;
7788 };
7789 /**
7790 * List the calling user's precedent entries (non-dismissed, newest first)
7791 * @description Returns the caller's non-dismissed precedent entries
7792 * (``dismissed_at IS NULL``) ordered by ``created_at DESC``. Pass
7793 * ``?pattern_kind=`` to filter to one classifier; omitting it returns
7794 * all non-dismissed entries. ``limit`` is clamped to [1, 200];
7795 * ``offset`` to [0, ∞).
7796 */
7797 get: {
7798 parameters: {
7799 query?: {
7800 /** @description Filter by precedent classifier; omit to return all non-dismissed entries. */
7801 pattern_kind?: string;
7802 /** @description Maximum number of entries to return (clamped to [1, 200]). */
7803 limit?: number;
7804 /** @description Zero-based index of the first result to return. */
7805 offset?: number;
7806 };
7807 header?: never;
7808 path?: never;
7809 cookie?: never;
7810 };
7811 requestBody?: never;
7812 responses: {
7813 /** @description Paginated list of precedent entries */
7814 200: {
7815 headers: {
7816 [name: string]: unknown;
7817 };
7818 content: {
7819 "application/json": components["schemas"]["PrecedentEntryListResponse"];
7820 };
7821 };
7822 /** @description Not authenticated */
7823 401: {
7824 headers: {
7825 [name: string]: unknown;
7826 };
7827 content?: never;
7828 };
7829 };
7830 };
7831 put?: never;
7832 post?: never;
7833 delete?: never;
7834 options?: never;
7835 head?: never;
7836 patch?: never;
7837 trace?: never;
7838 };
7839 "/api/v1/autonomous/precedents/{precedent_id}/dismiss": {
7840 parameters: {
7841 query?: never;
7842 header?: never;
7843 path?: never;
7844 cookie?: never;
7845 };
7846 get?: never;
7847 put?: never;
7848 /**
7849 * Dismiss a precedent entry (idempotent)
7850 * @description Sets ``dismissed_at=now(UTC)`` so the entry drops out of the board.
7851 * Re-dismissing leaves the original ``dismissed_at`` untouched.
7852 *
7853 * Another user's ``precedent_id`` returns 404. Audited.
7854 */
7855 post: {
7856 parameters: {
7857 query?: never;
7858 header?: never;
7859 path: {
7860 precedent_id: string;
7861 };
7862 cookie?: never;
7863 };
7864 requestBody?: never;
7865 responses: {
7866 /** @description Updated precedent entry (now dismissed) */
7867 200: {
7868 headers: {
7869 [name: string]: unknown;
7870 };
7871 content: {
7872 "application/json": components["schemas"]["PrecedentEntryRead"];
7873 };
7874 };
7875 /** @description Not authenticated */
7876 401: {
7877 headers: {
7878 [name: string]: unknown;
7879 };
7880 content?: never;
7881 };
7882 /** @description Precedent entry not found */
7883 404: {
7884 headers: {
7885 [name: string]: unknown;
7886 };
7887 content?: never;
7888 };
7889 };
7890 };
7891 delete?: never;
7892 options?: never;
7893 head?: never;
7894 patch?: never;
7895 trace?: never;
7896 };
7897 "/api/v1/autonomous/precedents/{precedent_id}/promote": {
7898 parameters: {
7899 query?: never;
7900 header?: never;
7901 path?: never;
7902 cookie?: never;
7903 };
7904 get?: never;
7905 put?: never;
7906 /**
7907 * Propose promoting a precedent into a Project's context (proposal only)
7908 * @description Creates a ``proposed`` project-context proposal linking the
7909 * precedent to ``project_id``. The ``suggested_md`` snippet is
7910 * derived server-side from the precedent's ``summary``.
7911 *
7912 * This endpoint does **NOT** mutate ``projects.context_md`` —
7913 * promotion is a proposal only; the user accepting it performs the
7914 * authorized write (ADR 0013 D5).
7915 *
7916 * Another user's ``precedent_id`` — or a ``project_id`` the caller
7917 * does not own — returns 404. Audited.
7918 */
7919 post: {
7920 parameters: {
7921 query?: never;
7922 header?: never;
7923 path: {
7924 precedent_id: string;
7925 };
7926 cookie?: never;
7927 };
7928 requestBody: {
7929 content: {
7930 "application/json": components["schemas"]["PromotePrecedentRequest"];
7931 };
7932 };
7933 responses: {
7934 /** @description Proposal created */
7935 201: {
7936 headers: {
7937 [name: string]: unknown;
7938 };
7939 content: {
7940 "application/json": components["schemas"]["ProjectContextProposalRead"];
7941 };
7942 };
7943 /** @description Not authenticated */
7944 401: {
7945 headers: {
7946 [name: string]: unknown;
7947 };
7948 content?: never;
7949 };
7950 /** @description Precedent or target project not found */
7951 404: {
7952 headers: {
7953 [name: string]: unknown;
7954 };
7955 content?: never;
7956 };
7957 };
7958 };
7959 delete?: never;
7960 options?: never;
7961 head?: never;
7962 patch?: never;
7963 trace?: never;
7964 };
7965 "/api/v1/autonomous/project-context-proposals": {
7966 parameters: {
7967 query?: never;
7968 header?: never;
7969 path?: never;
7970 cookie?: never;
7971 };
7972 /**
7973 * List the calling user's project-context proposals (newest first)
7974 * @description Returns the caller's project-context proposals ordered by
7975 * ``created_at DESC``. Pass ``?state=proposed|accepted|rejected``
7976 * and/or ``?project_id=`` to filter. ``limit`` is clamped to
7977 * [1, 200]; ``offset`` to [0, ∞).
7978 */
7979 get: {
7980 parameters: {
7981 query?: {
7982 /** @description Filter by proposal state. */
7983 state?: "proposed" | "accepted" | "rejected";
7984 /** @description Filter to proposals targeting one Project. */
7985 project_id?: string;
7986 /** @description Maximum number of proposals to return (clamped to [1, 200]). */
7987 limit?: number;
7988 /** @description Zero-based index of the first result to return. */
7989 offset?: number;
7990 };
7991 header?: never;
7992 path?: never;
7993 cookie?: never;
7994 };
7995 requestBody?: never;
7996 responses: {
7997 /** @description Paginated list of project-context proposals */
7998 200: {
7999 headers: {
8000 [name: string]: unknown;
8001 };
8002 content: {
8003 "application/json": components["schemas"]["ProjectContextProposalListResponse"];
8004 };
8005 };
8006 /** @description Not authenticated */
8007 401: {
8008 headers: {
8009 [name: string]: unknown;
8010 };
8011 content?: never;
8012 };
8013 };
8014 };
8015 put?: never;
8016 post?: never;
8017 delete?: never;
8018 options?: never;
8019 head?: never;
8020 patch?: never;
8021 trace?: never;
8022 };
8023 "/api/v1/autonomous/project-context-proposals/{proposal_id}/accept": {
8024 parameters: {
8025 query?: never;
8026 header?: never;
8027 path?: never;
8028 cookie?: never;
8029 };
8030 get?: never;
8031 put?: never;
8032 /**
8033 * Accept a proposal — append the suggested context to the Project (user-authorized write)
8034 * @description The user-authorized write (ADR 0013 D5): appends the proposal's
8035 * ``suggested_md`` to the target Project's ``context_md``
8036 * (initializing it if NULL), sets ``state='accepted'`` and
8037 * ``accepted_at``.
8038 *
8039 * Idempotent on re-accept: if already ``accepted``, returns the
8040 * current state without re-appending. A ``rejected`` proposal may be
8041 * accepted (rejected→accepted) and the append occurs.
8042 *
8043 * Another user's ``proposal_id`` returns 404. Audited.
8044 */
8045 post: {
8046 parameters: {
8047 query?: never;
8048 header?: never;
8049 path: {
8050 proposal_id: string;
8051 };
8052 cookie?: never;
8053 };
8054 requestBody?: never;
8055 responses: {
8056 /** @description Updated proposal (now accepted) */
8057 200: {
8058 headers: {
8059 [name: string]: unknown;
8060 };
8061 content: {
8062 "application/json": components["schemas"]["ProjectContextProposalRead"];
8063 };
8064 };
8065 /** @description Not authenticated */
8066 401: {
8067 headers: {
8068 [name: string]: unknown;
8069 };
8070 content?: never;
8071 };
8072 /** @description Proposal not found */
8073 404: {
8074 headers: {
8075 [name: string]: unknown;
8076 };
8077 content?: never;
8078 };
8079 };
8080 };
8081 delete?: never;
8082 options?: never;
8083 head?: never;
8084 patch?: never;
8085 trace?: never;
8086 };
8087 "/api/v1/autonomous/project-context-proposals/{proposal_id}/reject": {
8088 parameters: {
8089 query?: never;
8090 header?: never;
8091 path?: never;
8092 cookie?: never;
8093 };
8094 get?: never;
8095 put?: never;
8096 /**
8097 * Reject a proposal (does not touch Project context)
8098 * @description Sets ``state='rejected'`` and ``rejected_at``. Does NOT touch
8099 * ``projects.context_md``.
8100 *
8101 * Another user's ``proposal_id`` returns 404. Audited.
8102 */
8103 post: {
8104 parameters: {
8105 query?: never;
8106 header?: never;
8107 path: {
8108 proposal_id: string;
8109 };
8110 cookie?: never;
8111 };
8112 requestBody?: never;
8113 responses: {
8114 /** @description Updated proposal (now rejected) */
8115 200: {
8116 headers: {
8117 [name: string]: unknown;
8118 };
8119 content: {
8120 "application/json": components["schemas"]["ProjectContextProposalRead"];
8121 };
8122 };
8123 /** @description Not authenticated */
8124 401: {
8125 headers: {
8126 [name: string]: unknown;
8127 };
8128 content?: never;
8129 };
8130 /** @description Proposal not found */
8131 404: {
8132 headers: {
8133 [name: string]: unknown;
8134 };
8135 content?: never;
8136 };
8137 };
8138 };
8139 delete?: never;
8140 options?: never;
8141 head?: never;
8142 patch?: never;
8143 trace?: never;
8144 };
8145 "/api/v1/autonomous/schedules": {
8146 parameters: {
8147 query?: never;
8148 header?: never;
8149 path?: never;
8150 cookie?: never;
8151 };
8152 /**
8153 * List the calling user's autonomous schedules (non-deleted, newest first)
8154 * @description Returns the caller's non-deleted schedules ordered by
8155 * ``created_at DESC``. Optional ``?enabled=`` filter.
8156 */
8157 get: {
8158 parameters: {
8159 query?: {
8160 enabled?: boolean;
8161 limit?: number;
8162 offset?: number;
8163 };
8164 header?: never;
8165 path?: never;
8166 cookie?: never;
8167 };
8168 requestBody?: never;
8169 responses: {
8170 /** @description Paginated list of schedules */
8171 200: {
8172 headers: {
8173 [name: string]: unknown;
8174 };
8175 content: {
8176 "application/json": components["schemas"]["AutonomousScheduleListResponse"];
8177 };
8178 };
8179 /** @description Not authenticated */
8180 401: {
8181 headers: {
8182 [name: string]: unknown;
8183 };
8184 content?: never;
8185 };
8186 };
8187 };
8188 put?: never;
8189 /**
8190 * Create an autonomous schedule (cron-triggered run definition)
8191 * @description Validates ``cron_expr`` (a five-field cron string); invalid
8192 * expressions return 422. Seeds ``next_run_at`` from the cron
8193 * expression so the dispatcher can pick it up. Per-user isolated.
8194 */
8195 post: {
8196 parameters: {
8197 query?: never;
8198 header?: never;
8199 path?: never;
8200 cookie?: never;
8201 };
8202 requestBody: {
8203 content: {
8204 "application/json": components["schemas"]["AutonomousScheduleCreate"];
8205 };
8206 };
8207 responses: {
8208 /** @description Schedule created */
8209 201: {
8210 headers: {
8211 [name: string]: unknown;
8212 };
8213 content: {
8214 "application/json": components["schemas"]["AutonomousScheduleRead"];
8215 };
8216 };
8217 /** @description Not authenticated */
8218 401: {
8219 headers: {
8220 [name: string]: unknown;
8221 };
8222 content?: never;
8223 };
8224 /** @description Referenced project not found */
8225 404: {
8226 headers: {
8227 [name: string]: unknown;
8228 };
8229 content?: never;
8230 };
8231 /** @description Invalid cron expression */
8232 422: {
8233 headers: {
8234 [name: string]: unknown;
8235 };
8236 content?: never;
8237 };
8238 };
8239 };
8240 delete?: never;
8241 options?: never;
8242 head?: never;
8243 patch?: never;
8244 trace?: never;
8245 };
8246 "/api/v1/autonomous/schedules/{schedule_id}": {
8247 parameters: {
8248 query?: never;
8249 header?: never;
8250 path?: never;
8251 cookie?: never;
8252 };
8253 get?: never;
8254 put?: never;
8255 post?: never;
8256 /**
8257 * Soft-delete an autonomous schedule (returns 200 with updated entity)
8258 * @description Soft-deletes by setting ``deleted_at``. Returns 200 with the
8259 * updated entity (NOT 204 — FastAPI JSONResponse/204 pitfall).
8260 * A deleted schedule is excluded from list and the dispatcher;
8261 * re-delete returns 404. Another user's ``schedule_id`` returns 404.
8262 * Audited.
8263 */
8264 delete: {
8265 parameters: {
8266 query?: never;
8267 header?: never;
8268 path: {
8269 schedule_id: string;
8270 };
8271 cookie?: never;
8272 };
8273 requestBody?: never;
8274 responses: {
8275 /** @description Updated schedule (now soft-deleted) */
8276 200: {
8277 headers: {
8278 [name: string]: unknown;
8279 };
8280 content: {
8281 "application/json": components["schemas"]["AutonomousScheduleRead"];
8282 };
8283 };
8284 /** @description Not authenticated */
8285 401: {
8286 headers: {
8287 [name: string]: unknown;
8288 };
8289 content?: never;
8290 };
8291 /** @description Schedule not found */
8292 404: {
8293 headers: {
8294 [name: string]: unknown;
8295 };
8296 content?: never;
8297 };
8298 };
8299 };
8300 options?: never;
8301 head?: never;
8302 /**
8303 * Partially update an autonomous schedule (edit / enable / disable)
8304 * @description Partial update. If ``cron_expr`` changes it is re-validated (422
8305 * on invalid) and ``next_run_at`` is recomputed. Another user's
8306 * ``schedule_id`` returns 404. Audited.
8307 */
8308 patch: {
8309 parameters: {
8310 query?: never;
8311 header?: never;
8312 path: {
8313 schedule_id: string;
8314 };
8315 cookie?: never;
8316 };
8317 requestBody: {
8318 content: {
8319 "application/json": components["schemas"]["AutonomousScheduleUpdate"];
8320 };
8321 };
8322 responses: {
8323 /** @description Updated schedule */
8324 200: {
8325 headers: {
8326 [name: string]: unknown;
8327 };
8328 content: {
8329 "application/json": components["schemas"]["AutonomousScheduleRead"];
8330 };
8331 };
8332 /** @description Not authenticated */
8333 401: {
8334 headers: {
8335 [name: string]: unknown;
8336 };
8337 content?: never;
8338 };
8339 /** @description Schedule or referenced project not found */
8340 404: {
8341 headers: {
8342 [name: string]: unknown;
8343 };
8344 content?: never;
8345 };
8346 /** @description Invalid cron expression */
8347 422: {
8348 headers: {
8349 [name: string]: unknown;
8350 };
8351 content?: never;
8352 };
8353 };
8354 };
8355 trace?: never;
8356 };
8357 "/api/v1/autonomous/watches": {
8358 parameters: {
8359 query?: never;
8360 header?: never;
8361 path?: never;
8362 cookie?: never;
8363 };
8364 /**
8365 * List the calling user's autonomous watches (non-deleted, newest first)
8366 * @description Returns the caller's non-deleted watches ordered by
8367 * ``created_at DESC``. Optional ``?enabled=`` and
8368 * ``?knowledge_base_id=`` filters.
8369 */
8370 get: {
8371 parameters: {
8372 query?: {
8373 enabled?: boolean;
8374 knowledge_base_id?: string;
8375 limit?: number;
8376 offset?: number;
8377 };
8378 header?: never;
8379 path?: never;
8380 cookie?: never;
8381 };
8382 requestBody?: never;
8383 responses: {
8384 /** @description Paginated list of watches */
8385 200: {
8386 headers: {
8387 [name: string]: unknown;
8388 };
8389 content: {
8390 "application/json": components["schemas"]["AutonomousWatchListResponse"];
8391 };
8392 };
8393 /** @description Not authenticated */
8394 401: {
8395 headers: {
8396 [name: string]: unknown;
8397 };
8398 content?: never;
8399 };
8400 };
8401 };
8402 put?: never;
8403 /**
8404 * Create an autonomous watch (KB-arrival-triggered run definition)
8405 * @description Creates a watch on a knowledge base the caller owns; document
8406 * arrivals (KB attach) then spawn an autonomous session. The caller
8407 * must own the target ``knowledge_base_id`` — a KB they cannot see
8408 * returns 404 (KB-sharing is out of scope). Per-user isolated.
8409 */
8410 post: {
8411 parameters: {
8412 query?: never;
8413 header?: never;
8414 path?: never;
8415 cookie?: never;
8416 };
8417 requestBody: {
8418 content: {
8419 "application/json": components["schemas"]["AutonomousWatchCreate"];
8420 };
8421 };
8422 responses: {
8423 /** @description Watch created */
8424 201: {
8425 headers: {
8426 [name: string]: unknown;
8427 };
8428 content: {
8429 "application/json": components["schemas"]["AutonomousWatchRead"];
8430 };
8431 };
8432 /** @description Not authenticated */
8433 401: {
8434 headers: {
8435 [name: string]: unknown;
8436 };
8437 content?: never;
8438 };
8439 /** @description Target knowledge base or referenced project not found */
8440 404: {
8441 headers: {
8442 [name: string]: unknown;
8443 };
8444 content?: never;
8445 };
8446 };
8447 };
8448 delete?: never;
8449 options?: never;
8450 head?: never;
8451 patch?: never;
8452 trace?: never;
8453 };
8454 "/api/v1/autonomous/watches/{watch_id}": {
8455 parameters: {
8456 query?: never;
8457 header?: never;
8458 path?: never;
8459 cookie?: never;
8460 };
8461 get?: never;
8462 put?: never;
8463 post?: never;
8464 /**
8465 * Soft-delete an autonomous watch (returns 200 with updated entity)
8466 * @description Soft-deletes by setting ``deleted_at``. Returns 200 with the
8467 * updated entity (NOT 204 — FastAPI JSONResponse/204 pitfall).
8468 * A deleted watch is excluded from list and the KB-arrival trigger;
8469 * re-delete returns 404. Another user's ``watch_id`` returns 404.
8470 * Audited.
8471 */
8472 delete: {
8473 parameters: {
8474 query?: never;
8475 header?: never;
8476 path: {
8477 watch_id: string;
8478 };
8479 cookie?: never;
8480 };
8481 requestBody?: never;
8482 responses: {
8483 /** @description Updated watch (now soft-deleted) */
8484 200: {
8485 headers: {
8486 [name: string]: unknown;
8487 };
8488 content: {
8489 "application/json": components["schemas"]["AutonomousWatchRead"];
8490 };
8491 };
8492 /** @description Not authenticated */
8493 401: {
8494 headers: {
8495 [name: string]: unknown;
8496 };
8497 content?: never;
8498 };
8499 /** @description Watch not found */
8500 404: {
8501 headers: {
8502 [name: string]: unknown;
8503 };
8504 content?: never;
8505 };
8506 };
8507 };
8508 options?: never;
8509 head?: never;
8510 /**
8511 * Partially update an autonomous watch (enable / disable / retarget)
8512 * @description Partial update of ``enabled`` / ``playbook_id`` / ``skill_ref``.
8513 * The watch's ``knowledge_base_id`` is immutable. Another user's
8514 * ``watch_id`` returns 404. Audited.
8515 */
8516 patch: {
8517 parameters: {
8518 query?: never;
8519 header?: never;
8520 path: {
8521 watch_id: string;
8522 };
8523 cookie?: never;
8524 };
8525 requestBody: {
8526 content: {
8527 "application/json": components["schemas"]["AutonomousWatchUpdate"];
8528 };
8529 };
8530 responses: {
8531 /** @description Updated watch */
8532 200: {
8533 headers: {
8534 [name: string]: unknown;
8535 };
8536 content: {
8537 "application/json": components["schemas"]["AutonomousWatchRead"];
8538 };
8539 };
8540 /** @description Not authenticated */
8541 401: {
8542 headers: {
8543 [name: string]: unknown;
8544 };
8545 content?: never;
8546 };
8547 /** @description Watch or referenced project not found */
8548 404: {
8549 headers: {
8550 [name: string]: unknown;
8551 };
8552 content?: never;
8553 };
8554 };
8555 };
8556 trace?: never;
8557 };
8558 "/api/v1/autonomous/notifications": {
8559 parameters: {
8560 query?: never;
8561 header?: never;
8562 path?: never;
8563 cookie?: never;
8564 };
8565 /**
8566 * List the calling user's autonomous notifications (newest first)
8567 * @description Returns the caller's notifications ordered by ``created_at DESC``.
8568 * Pass ``?unread=true`` to narrow to unread rows (``read_at IS
8569 * NULL``). Per-user isolated.
8570 */
8571 get: {
8572 parameters: {
8573 query?: {
8574 unread?: boolean;
8575 limit?: number;
8576 offset?: number;
8577 };
8578 header?: never;
8579 path?: never;
8580 cookie?: never;
8581 };
8582 requestBody?: never;
8583 responses: {
8584 /** @description Paginated list of notifications */
8585 200: {
8586 headers: {
8587 [name: string]: unknown;
8588 };
8589 content: {
8590 "application/json": components["schemas"]["AutonomousNotificationListResponse"];
8591 };
8592 };
8593 /** @description Not authenticated */
8594 401: {
8595 headers: {
8596 [name: string]: unknown;
8597 };
8598 content?: never;
8599 };
8600 };
8601 };
8602 put?: never;
8603 post?: never;
8604 delete?: never;
8605 options?: never;
8606 head?: never;
8607 patch?: never;
8608 trace?: never;
8609 };
8610 "/api/v1/autonomous/notifications/{notification_id}/read": {
8611 parameters: {
8612 query?: never;
8613 header?: never;
8614 path?: never;
8615 cookie?: never;
8616 };
8617 get?: never;
8618 put?: never;
8619 /**
8620 * Mark an autonomous notification read (the dismiss action; idempotent)
8621 * @description Sets ``read_at`` if currently NULL; idempotent (re-read preserves
8622 * the original timestamp). "Read" IS the dismiss action — a read
8623 * notification drops out of ``?unread=true``. Another user's
8624 * ``notification_id`` returns 404. Audited.
8625 */
8626 post: {
8627 parameters: {
8628 query?: never;
8629 header?: never;
8630 path: {
8631 notification_id: string;
8632 };
8633 cookie?: never;
8634 };
8635 requestBody?: never;
8636 responses: {
8637 /** @description Updated notification (now read) */
8638 200: {
8639 headers: {
8640 [name: string]: unknown;
8641 };
8642 content: {
8643 "application/json": components["schemas"]["AutonomousNotificationRead"];
8644 };
8645 };
8646 /** @description Not authenticated */
8647 401: {
8648 headers: {
8649 [name: string]: unknown;
8650 };
8651 content?: never;
8652 };
8653 /** @description Notification not found */
8654 404: {
8655 headers: {
8656 [name: string]: unknown;
8657 };
8658 content?: never;
8659 };
8660 };
8661 };
8662 delete?: never;
8663 options?: never;
8664 head?: never;
8665 patch?: never;
8666 trace?: never;
8667 };
8668 "/api/v1/autonomous/run-now": {
8669 parameters: {
8670 query?: never;
8671 header?: never;
8672 path?: never;
8673 cookie?: never;
8674 };
8675 get?: never;
8676 put?: never;
8677 /**
8678 * Run a skill or playbook once now (one-off manual autonomous session)
8679 * @description Spawns a single ``trigger_kind='manual'`` autonomous session so a
8680 * user can test what a skill/playbook does — and inspect the
8681 * resulting receipt — before arming it as a schedule or watch.
8682 * Exactly one of ``playbook_id`` / ``skill_ref`` must be set (zero
8683 * or both → 422). ``target_kb_id`` / ``project_id`` are optional
8684 * scope; ``max_cost_usd`` is the per-run cap (NULL falls back to the
8685 * config default so R4 always arms). Gated by opt-in
8686 * (``autonomous_enabled``); the spawned session runs under the same
8687 * R4/R5/R6 brakes as every other session. Per-user isolated. Audited.
8688 */
8689 post: {
8690 parameters: {
8691 query?: never;
8692 header?: never;
8693 path?: never;
8694 cookie?: never;
8695 };
8696 requestBody: {
8697 content: {
8698 "application/json": components["schemas"]["AutonomousManualRunRequest"];
8699 };
8700 };
8701 responses: {
8702 /** @description Session spawned */
8703 201: {
8704 headers: {
8705 [name: string]: unknown;
8706 };
8707 content: {
8708 "application/json": components["schemas"]["AutonomousSessionRead"];
8709 };
8710 };
8711 /** @description Not authenticated */
8712 401: {
8713 headers: {
8714 [name: string]: unknown;
8715 };
8716 content?: never;
8717 };
8718 /** @description Autonomous layer not enabled for this user */
8719 403: {
8720 headers: {
8721 [name: string]: unknown;
8722 };
8723 content?: never;
8724 };
8725 /** @description Referenced project not found */
8726 404: {
8727 headers: {
8728 [name: string]: unknown;
8729 };
8730 content?: never;
8731 };
8732 /** @description Invalid target (need exactly one of playbook_id/skill_ref) */
8733 422: {
8734 headers: {
8735 [name: string]: unknown;
8736 };
8737 content?: never;
8738 };
8739 };
8740 };
8741 delete?: never;
8742 options?: never;
8743 head?: never;
8744 patch?: never;
8745 trace?: never;
8746 };
8747 "/api/v1/research/capabilities": {
8748 parameters: {
8749 query?: never;
8750 header?: never;
8751 path?: never;
8752 cookie?: never;
8753 };
8754 /**
8755 * Report whether case-law research is enabled on this server
8756 * @description WS3b. Returns a positive "research enabled?" signal derived from the
8757 * gateway's sanitised config. ``enabled`` is ``true`` when at least one
8758 * ``courtlistener`` tool-provider is declared in ``gateway.yaml``;
8759 * ``false`` otherwise. The UI uses this to render a calm "not configured"
8760 * gate rather than treating an absent CourtListener as an outage.
8761 * Requires an authenticated user (bearer token).
8762 */
8763 get: {
8764 parameters: {
8765 query?: never;
8766 header?: never;
8767 path?: never;
8768 cookie?: never;
8769 };
8770 requestBody?: never;
8771 responses: {
8772 /** @description Research capability status */
8773 200: {
8774 headers: {
8775 [name: string]: unknown;
8776 };
8777 content: {
8778 "application/json": {
8779 enabled: boolean;
8780 providers: {
8781 name: string;
8782 type: string;
8783 }[];
8784 };
8785 };
8786 };
8787 /** @description Not authenticated */
8788 401: {
8789 headers: {
8790 [name: string]: unknown;
8791 };
8792 content: {
8793 "application/json": components["schemas"]["Error"];
8794 };
8795 };
8796 };
8797 };
8798 put?: never;
8799 post?: never;
8800 delete?: never;
8801 options?: never;
8802 head?: never;
8803 patch?: never;
8804 trace?: never;
8805 };
8806 "/api/v1/research/verify-citations": {
8807 parameters: {
8808 query?: never;
8809 header?: never;
8810 path?: never;
8811 cookie?: never;
8812 };
8813 get?: never;
8814 put?: never;
8815 /**
8816 * Verify citations found in a text block
8817 * @description WS3b. Passes the supplied text to the CourtListener gateway tool
8818 * ``verify_citations`` and returns the per-citation verification
8819 * results (HTTP status, matching cluster ids). Stateless — no DB
8820 * write. Requires an authenticated user (bearer token).
8821 */
8822 post: {
8823 parameters: {
8824 query?: never;
8825 header?: never;
8826 path?: never;
8827 cookie?: never;
8828 };
8829 requestBody: {
8830 content: {
8831 "application/json": {
8832 text: string;
8833 };
8834 };
8835 };
8836 responses: {
8837 /** @description Citation verification results */
8838 200: {
8839 headers: {
8840 [name: string]: unknown;
8841 };
8842 content: {
8843 "application/json": {
8844 citations?: {
8845 citation?: string | null;
8846 normalized_citations?: string[];
8847 status?: number | null;
8848 error_message?: string | null;
8849 clusters?: {
8850 id?: number | null;
8851 case_name?: string | null;
8852 absolute_url?: string | null;
8853 }[];
8854 }[];
8855 };
8856 };
8857 };
8858 /** @description Not authenticated */
8859 401: {
8860 headers: {
8861 [name: string]: unknown;
8862 };
8863 content: {
8864 "application/json": components["schemas"]["Error"];
8865 };
8866 };
8867 };
8868 };
8869 delete?: never;
8870 options?: never;
8871 head?: never;
8872 patch?: never;
8873 trace?: never;
8874 };
8875 "/api/v1/research/search": {
8876 parameters: {
8877 query?: never;
8878 header?: never;
8879 path?: never;
8880 cookie?: never;
8881 };
8882 get?: never;
8883 put?: never;
8884 /**
8885 * Search case law via CourtListener
8886 * @description WS3b. Proxies a full-text case-law search to the CourtListener
8887 * gateway tool ``search_case_law``. Returns a paginated result set
8888 * with case metadata. Stateless — no DB write. Requires an
8889 * authenticated user (bearer token).
8890 */
8891 post: {
8892 parameters: {
8893 query?: never;
8894 header?: never;
8895 path?: never;
8896 cookie?: never;
8897 };
8898 requestBody: {
8899 content: {
8900 "application/json": {
8901 q: string;
8902 court?: string | null;
8903 order_by?: string | null;
8904 /** @description Opaque pagination cursor from a prior response's next_cursor; fetch the next page. */
8905 cursor?: string | null;
8906 };
8907 };
8908 };
8909 responses: {
8910 /** @description Search results */
8911 200: {
8912 headers: {
8913 [name: string]: unknown;
8914 };
8915 content: {
8916 "application/json": {
8917 count?: number | null;
8918 results?: {
8919 [key: string]: unknown;
8920 }[];
8921 next_cursor?: string | null;
8922 };
8923 };
8924 };
8925 /** @description Not authenticated */
8926 401: {
8927 headers: {
8928 [name: string]: unknown;
8929 };
8930 content: {
8931 "application/json": components["schemas"]["Error"];
8932 };
8933 };
8934 };
8935 };
8936 delete?: never;
8937 options?: never;
8938 head?: never;
8939 patch?: never;
8940 trace?: never;
8941 };
8942 "/api/v1/research/clusters/{cluster_id}": {
8943 parameters: {
8944 query?: never;
8945 header?: never;
8946 path?: never;
8947 cookie?: never;
8948 };
8949 /**
8950 * Fetch and cache a CourtListener opinion cluster
8951 * @description WS3b. Read-through cache: if the cluster is already in the DB
8952 * the cached metadata is returned immediately; otherwise the
8953 * gateway tool ``get_cases`` is called, the opinion plaintext is
8954 * stored in object storage, and the metadata is persisted in the
8955 * DB. Requires an authenticated user (bearer token).
8956 */
8957 get: {
8958 parameters: {
8959 query?: never;
8960 header?: never;
8961 path: {
8962 cluster_id: number;
8963 };
8964 cookie?: never;
8965 };
8966 requestBody?: never;
8967 responses: {
8968 /** @description Cluster metadata with opinion list */
8969 200: {
8970 headers: {
8971 [name: string]: unknown;
8972 };
8973 content: {
8974 "application/json": {
8975 cluster: {
8976 cluster_id: number;
8977 case_name?: string | null;
8978 court?: string | null;
8979 date_filed?: string | null;
8980 absolute_url?: string | null;
8981 };
8982 opinions: {
8983 opinion_id: number;
8984 /** @enum {string|null} */
8985 text_field_used?: "html_with_citations" | "html_columbia" | "html_lawbox" | "xml_harvard" | "html_anon_2020" | "html" | "plain_text" | null;
8986 char_length: number;
8987 }[];
8988 };
8989 };
8990 };
8991 /** @description Not authenticated */
8992 401: {
8993 headers: {
8994 [name: string]: unknown;
8995 };
8996 content: {
8997 "application/json": components["schemas"]["Error"];
8998 };
8999 };
9000 };
9001 };
9002 put?: never;
9003 post?: never;
9004 delete?: never;
9005 options?: never;
9006 head?: never;
9007 patch?: never;
9008 trace?: never;
9009 };
9010 "/api/v1/research/opinions/{opinion_id}": {
9011 parameters: {
9012 query?: never;
9013 header?: never;
9014 path?: never;
9015 cookie?: never;
9016 };
9017 /**
9018 * Read cached opinion plaintext
9019 * @description WS3b. Returns the full plaintext of a previously fetched opinion
9020 * from object storage. Returns 404 if the cluster containing this
9021 * opinion was never fetched (call
9022 * ``GET /api/v1/research/clusters/{cluster_id}`` first). Requires
9023 * an authenticated user (bearer token).
9024 */
9025 get: {
9026 parameters: {
9027 query?: never;
9028 header?: never;
9029 path: {
9030 opinion_id: number;
9031 };
9032 cookie?: never;
9033 };
9034 requestBody?: never;
9035 responses: {
9036 /** @description Opinion plaintext */
9037 200: {
9038 headers: {
9039 [name: string]: unknown;
9040 };
9041 content: {
9042 "application/json": {
9043 opinion_id: number;
9044 cluster_id: number;
9045 /** @enum {string|null} */
9046 text_field_used?: "html_with_citations" | "html_columbia" | "html_lawbox" | "xml_harvard" | "html_anon_2020" | "html" | "plain_text" | null;
9047 text: string;
9048 };
9049 };
9050 };
9051 /** @description Not authenticated */
9052 401: {
9053 headers: {
9054 [name: string]: unknown;
9055 };
9056 content: {
9057 "application/json": components["schemas"]["Error"];
9058 };
9059 };
9060 /** @description Opinion not yet fetched; call GET /clusters/{id} first */
9061 404: {
9062 headers: {
9063 [name: string]: unknown;
9064 };
9065 content: {
9066 "application/json": components["schemas"]["Error"];
9067 };
9068 };
9069 };
9070 };
9071 put?: never;
9072 post?: never;
9073 delete?: never;
9074 options?: never;
9075 head?: never;
9076 patch?: never;
9077 trace?: never;
9078 };
9079 "/api/v1/research/find-in-case": {
9080 parameters: {
9081 query?: never;
9082 header?: never;
9083 path?: never;
9084 cookie?: never;
9085 };
9086 get?: never;
9087 put?: never;
9088 /**
9089 * Find keyword matches within a cached opinion
9090 * @description WS3b. Performs a case-insensitive substring search over the
9091 * cached plaintext of ``opinion_id``, returning up to
9092 * ``max_matches`` snippets with character positions. Returns 404
9093 * if the opinion was never fetched. Requires an authenticated
9094 * user (bearer token).
9095 */
9096 post: {
9097 parameters: {
9098 query?: never;
9099 header?: never;
9100 path?: never;
9101 cookie?: never;
9102 };
9103 requestBody: {
9104 content: {
9105 "application/json": {
9106 opinion_id: number;
9107 query: string;
9108 /** @default 3 */
9109 max_matches?: number;
9110 };
9111 };
9112 };
9113 responses: {
9114 /** @description Match snippets */
9115 200: {
9116 headers: {
9117 [name: string]: unknown;
9118 };
9119 content: {
9120 "application/json": {
9121 opinion_id: number;
9122 matches: {
9123 position: number;
9124 snippet: string;
9125 }[];
9126 };
9127 };
9128 };
9129 /** @description Not authenticated */
9130 401: {
9131 headers: {
9132 [name: string]: unknown;
9133 };
9134 content: {
9135 "application/json": components["schemas"]["Error"];
9136 };
9137 };
9138 /** @description Opinion not yet fetched; call GET /clusters/{id} first */
9139 404: {
9140 headers: {
9141 [name: string]: unknown;
9142 };
9143 content: {
9144 "application/json": components["schemas"]["Error"];
9145 };
9146 };
9147 };
9148 };
9149 delete?: never;
9150 options?: never;
9151 head?: never;
9152 patch?: never;
9153 trace?: never;
9154 };
9155 "/api/v1/admin/mcp": {
9156 parameters: {
9157 query?: never;
9158 header?: never;
9159 path?: never;
9160 cookie?: never;
9161 };
9162 /**
9163 * List configured MCP servers and their cached tools (admin only)
9164 * @description WS2/PR4b. Returns the operator's configured MCP servers (sourced
9165 * from gateway config, type==mcp) together with each server's
9166 * discovery-cached tools and their ``enabled`` toggle state. The
9167 * caller's bearer token must have ``is_admin = true`` or the
9168 * endpoint returns 403 ``forbidden``.
9169 */
9170 get: {
9171 parameters: {
9172 query?: never;
9173 header?: never;
9174 path?: never;
9175 cookie?: never;
9176 };
9177 requestBody?: never;
9178 responses: {
9179 /** @description MCP servers with cached tools */
9180 200: {
9181 headers: {
9182 [name: string]: unknown;
9183 };
9184 content: {
9185 "application/json": components["schemas"]["MCPServersResponse"];
9186 };
9187 };
9188 /** @description Not authenticated */
9189 401: {
9190 headers: {
9191 [name: string]: unknown;
9192 };
9193 content: {
9194 "application/json": components["schemas"]["Error"];
9195 };
9196 };
9197 /** @description Caller is not an admin */
9198 403: {
9199 headers: {
9200 [name: string]: unknown;
9201 };
9202 content: {
9203 "application/json": components["schemas"]["Error"];
9204 };
9205 };
9206 };
9207 };
9208 put?: never;
9209 post?: never;
9210 delete?: never;
9211 options?: never;
9212 head?: never;
9213 patch?: never;
9214 trace?: never;
9215 };
9216 "/api/v1/admin/mcp/{server}/refresh": {
9217 parameters: {
9218 query?: never;
9219 header?: never;
9220 path: {
9221 /** @description MCP server name (as returned by the gateway config). */
9222 server: string;
9223 };
9224 cookie?: never;
9225 };
9226 get?: never;
9227 put?: never;
9228 /**
9229 * Re-discover and reconcile a server's tools (admin only)
9230 * @description WS2/PR4b. Triggers a fresh tool-discovery pass against the named
9231 * MCP server through the gateway (PR4a's GET /v1/tools/{provider}).
9232 * The discovery cache is reconciled: new tools are inserted with
9233 * ``enabled=true``; surviving tools preserve their existing
9234 * ``enabled`` flag; stale tools (no longer returned) are removed.
9235 * Writes a ``mcp.tools_refreshed`` audit row. 403 when the caller
9236 * is not an admin.
9237 */
9238 post: {
9239 parameters: {
9240 query?: never;
9241 header?: never;
9242 path: {
9243 /** @description MCP server name (as returned by the gateway config). */
9244 server: string;
9245 };
9246 cookie?: never;
9247 };
9248 requestBody?: never;
9249 responses: {
9250 /** @description Refresh complete; returns the updated tool list */
9251 200: {
9252 headers: {
9253 [name: string]: unknown;
9254 };
9255 content: {
9256 "application/json": components["schemas"]["MCPRefreshResponse"];
9257 };
9258 };
9259 /** @description Not authenticated */
9260 401: {
9261 headers: {
9262 [name: string]: unknown;
9263 };
9264 content: {
9265 "application/json": components["schemas"]["Error"];
9266 };
9267 };
9268 /** @description Caller is not an admin */
9269 403: {
9270 headers: {
9271 [name: string]: unknown;
9272 };
9273 content: {
9274 "application/json": components["schemas"]["Error"];
9275 };
9276 };
9277 };
9278 };
9279 delete?: never;
9280 options?: never;
9281 head?: never;
9282 patch?: never;
9283 trace?: never;
9284 };
9285 "/api/v1/admin/mcp/{server}/tools/{tool}": {
9286 parameters: {
9287 query?: never;
9288 header?: never;
9289 path: {
9290 /** @description MCP server name. */
9291 server: string;
9292 /** @description Tool name within the server's discovery cache. */
9293 tool: string;
9294 };
9295 cookie?: never;
9296 };
9297 get?: never;
9298 put?: never;
9299 post?: never;
9300 delete?: never;
9301 options?: never;
9302 head?: never;
9303 /**
9304 * Enable or disable a cached MCP tool (admin only)
9305 * @description WS2/PR4b. Toggles the ``enabled`` flag on a single cached tool.
9306 * Disabled tools are not exposed to the model in the chat tool-loop
9307 * (PR5). 404 when the tool is not in the discovery cache (run
9308 * ``POST .../refresh`` first). Writes a ``mcp.tool_enabled`` audit
9309 * row when enabling, ``mcp.tool_disabled`` when disabling. 403 when
9310 * the caller is not an admin.
9311 */
9312 patch: {
9313 parameters: {
9314 query?: never;
9315 header?: never;
9316 path: {
9317 /** @description MCP server name. */
9318 server: string;
9319 /** @description Tool name within the server's discovery cache. */
9320 tool: string;
9321 };
9322 cookie?: never;
9323 };
9324 requestBody: {
9325 content: {
9326 "application/json": components["schemas"]["MCPToolEnableRequest"];
9327 };
9328 };
9329 responses: {
9330 /** @description Tool updated; returns the updated tool view */
9331 200: {
9332 headers: {
9333 [name: string]: unknown;
9334 };
9335 content: {
9336 "application/json": components["schemas"]["MCPToolView"];
9337 };
9338 };
9339 /** @description Not authenticated */
9340 401: {
9341 headers: {
9342 [name: string]: unknown;
9343 };
9344 content: {
9345 "application/json": components["schemas"]["Error"];
9346 };
9347 };
9348 /** @description Caller is not an admin */
9349 403: {
9350 headers: {
9351 [name: string]: unknown;
9352 };
9353 content: {
9354 "application/json": components["schemas"]["Error"];
9355 };
9356 };
9357 /** @description Tool not in discovery cache */
9358 404: {
9359 headers: {
9360 [name: string]: unknown;
9361 };
9362 content: {
9363 "application/json": components["schemas"]["Error"];
9364 };
9365 };
9366 };
9367 };
9368 trace?: never;
9369 };
9370 "/api/v1/mcp/oauth": {
9371 parameters: {
9372 query?: never;
9373 header?: never;
9374 path?: never;
9375 cookie?: never;
9376 };
9377 /**
9378 * List OAuth connection status for all connectable MCP servers (per-user)
9379 * @description PR4d Ask 1. ActiveUser-gated (bearer). Returns one entry per
9380 * configured OAuth-type MCP server together with the calling user's
9381 * connection state (``connected``, ``scopes``, ``expires_at``).
9382 * Token bytes are never exposed. Results are ordered by server name
9383 * for stable output.
9384 */
9385 get: {
9386 parameters: {
9387 query?: never;
9388 header?: never;
9389 path?: never;
9390 cookie?: never;
9391 };
9392 requestBody?: never;
9393 responses: {
9394 /** @description Per-user OAuth connection list */
9395 200: {
9396 headers: {
9397 [name: string]: unknown;
9398 };
9399 content: {
9400 "application/json": components["schemas"]["MCPOAuthServersResponse"];
9401 };
9402 };
9403 /** @description Not authenticated */
9404 401: {
9405 headers: {
9406 [name: string]: unknown;
9407 };
9408 content: {
9409 "application/json": components["schemas"]["Error"];
9410 };
9411 };
9412 };
9413 };
9414 put?: never;
9415 post?: never;
9416 delete?: never;
9417 options?: never;
9418 head?: never;
9419 patch?: never;
9420 trace?: never;
9421 };
9422 "/api/v1/mcp/oauth/{server}/authorize": {
9423 parameters: {
9424 query?: never;
9425 header?: never;
9426 path: {
9427 /** @description MCP server name (as returned by the gateway config). */
9428 server: string;
9429 };
9430 cookie?: never;
9431 };
9432 /**
9433 * Start the per-user OAuth flow for an MCP server
9434 * @description PR4c. ActiveUser-gated (bearer). Mints PKCE state, persists a
9435 * single-use mcp_oauth_state row, and returns a 302 redirect to the
9436 * authorization server's authorize endpoint. The callback URL is
9437 * wired to GET /api/v1/mcp/oauth/{server}/callback.
9438 */
9439 get: {
9440 parameters: {
9441 query?: never;
9442 header?: never;
9443 path: {
9444 /** @description MCP server name (as returned by the gateway config). */
9445 server: string;
9446 };
9447 cookie?: never;
9448 };
9449 requestBody?: never;
9450 responses: {
9451 /** @description Redirect to the authorization server authorize endpoint */
9452 302: {
9453 headers: {
9454 /** @description Authorization server authorize URL with PKCE parameters. */
9455 Location?: string;
9456 [name: string]: unknown;
9457 };
9458 content?: never;
9459 };
9460 /** @description Not authenticated */
9461 401: {
9462 headers: {
9463 [name: string]: unknown;
9464 };
9465 content: {
9466 "application/json": components["schemas"]["Error"];
9467 };
9468 };
9469 /** @description Server is not a configured OAuth MCP provider */
9470 404: {
9471 headers: {
9472 [name: string]: unknown;
9473 };
9474 content: {
9475 "application/json": components["schemas"]["Error"];
9476 };
9477 };
9478 };
9479 };
9480 put?: never;
9481 post?: never;
9482 delete?: never;
9483 options?: never;
9484 head?: never;
9485 patch?: never;
9486 trace?: never;
9487 };
9488 "/api/v1/mcp/oauth/{server}/callback": {
9489 parameters: {
9490 query?: never;
9491 header?: never;
9492 path: {
9493 /** @description MCP server name. */
9494 server: string;
9495 };
9496 cookie?: never;
9497 };
9498 /**
9499 * OAuth callback — receive the authorization code from the AS
9500 * @description PR4c. PUBLIC (no bearer auth). The browser is redirected here by
9501 * the authorization server after the user grants consent. The caller
9502 * is identified via the single-use, TTL-bounded mcp_oauth_state row
9503 * (``state`` IS the binding). On success, tokens are encrypted and
9504 * stored and a mcp.oauth_connected audit row is written. Returns 200
9505 * with the connection summary.
9506 */
9507 get: {
9508 parameters: {
9509 query: {
9510 /** @description Authorization code issued by the AS. */
9511 code: string;
9512 /** @description Opaque state value echoed from the authorize request. */
9513 state: string;
9514 /** @description Issuer identifier (RFC 9207); required when the AS advertised support. */
9515 iss?: string;
9516 };
9517 header?: never;
9518 path: {
9519 /** @description MCP server name. */
9520 server: string;
9521 };
9522 cookie?: never;
9523 };
9524 requestBody?: never;
9525 responses: {
9526 /** @description OAuth flow completed; tokens stored */
9527 200: {
9528 headers: {
9529 [name: string]: unknown;
9530 };
9531 content: {
9532 "application/json": components["schemas"]["MCPOAuthCallbackResponse"];
9533 };
9534 };
9535 /** @description Unknown, expired, or replayed state; iss validation failure */
9536 400: {
9537 headers: {
9538 [name: string]: unknown;
9539 };
9540 content: {
9541 "application/json": components["schemas"]["Error"];
9542 };
9543 };
9544 /** @description Authorization server returned an error on code exchange */
9545 502: {
9546 headers: {
9547 [name: string]: unknown;
9548 };
9549 content: {
9550 "application/json": components["schemas"]["Error"];
9551 };
9552 };
9553 };
9554 };
9555 put?: never;
9556 post?: never;
9557 delete?: never;
9558 options?: never;
9559 head?: never;
9560 patch?: never;
9561 trace?: never;
9562 };
9563 "/api/v1/mcp/oauth/{server}/status": {
9564 parameters: {
9565 query?: never;
9566 header?: never;
9567 path: {
9568 /** @description MCP server name. */
9569 server: string;
9570 };
9571 cookie?: never;
9572 };
9573 /**
9574 * Check the calling user's OAuth connection state for an MCP server
9575 * @description PR4c. ActiveUser-gated (bearer). Returns whether a stored token
9576 * exists for the (user, server) pair, the granted scopes, and the
9577 * token expiry. Token bytes are never exposed.
9578 */
9579 get: {
9580 parameters: {
9581 query?: never;
9582 header?: never;
9583 path: {
9584 /** @description MCP server name. */
9585 server: string;
9586 };
9587 cookie?: never;
9588 };
9589 requestBody?: never;
9590 responses: {
9591 /** @description Connection status */
9592 200: {
9593 headers: {
9594 [name: string]: unknown;
9595 };
9596 content: {
9597 "application/json": components["schemas"]["MCPOAuthStatusResponse"];
9598 };
9599 };
9600 /** @description Not authenticated */
9601 401: {
9602 headers: {
9603 [name: string]: unknown;
9604 };
9605 content: {
9606 "application/json": components["schemas"]["Error"];
9607 };
9608 };
9609 };
9610 };
9611 put?: never;
9612 post?: never;
9613 delete?: never;
9614 options?: never;
9615 head?: never;
9616 patch?: never;
9617 trace?: never;
9618 };
9619 "/api/v1/mcp/oauth/{server}": {
9620 parameters: {
9621 query?: never;
9622 header?: never;
9623 path: {
9624 /** @description MCP server name. */
9625 server: string;
9626 };
9627 cookie?: never;
9628 };
9629 get?: never;
9630 put?: never;
9631 post?: never;
9632 /**
9633 * Revoke the calling user's stored OAuth tokens for an MCP server
9634 * @description PR4c. ActiveUser-gated (bearer). Deletes the stored (user, server)
9635 * token row. Idempotent — returns 204 even when no token was stored.
9636 * AS-side revocation (RFC 7009) is not called in v1 (DE filed).
9637 * Writes a mcp.oauth_disconnected audit row when a row was removed.
9638 */
9639 delete: {
9640 parameters: {
9641 query?: never;
9642 header?: never;
9643 path: {
9644 /** @description MCP server name. */
9645 server: string;
9646 };
9647 cookie?: never;
9648 };
9649 requestBody?: never;
9650 responses: {
9651 /** @description Token deleted (or was not present) */
9652 204: {
9653 headers: {
9654 [name: string]: unknown;
9655 };
9656 content?: never;
9657 };
9658 /** @description Not authenticated */
9659 401: {
9660 headers: {
9661 [name: string]: unknown;
9662 };
9663 content: {
9664 "application/json": components["schemas"]["Error"];
9665 };
9666 };
9667 };
9668 };
9669 options?: never;
9670 head?: never;
9671 patch?: never;
9672 trace?: never;
9673 };
9674}
9675export type webhooks = Record<string, never>;
9676export interface components {
9677 schemas: {
9678 /**
9679 * @description Request body for `POST /api/v1/integrations/slack/workspaces`
9680 * (M3-D1). Shape matches what `slack-bridge/app/oauth.py`
9681 * constructs from Slack's `oauth.v2.access` response after the
9682 * operator completes consent. The bridge → api contract is
9683 * position-coupled to this shape; renames here would break it.
9684 */
9685 SlackWorkspaceCreate: {
9686 /**
9687 * @description Slack workspace id (T0...).
9688 * @example T01234567
9689 */
9690 team_id: string;
9691 /**
9692 * @description Workspace display name at install time.
9693 * @example Acme Legal
9694 */
9695 team_name: string;
9696 /**
9697 * @description The xoxb- bot user OAuth token Slack returned. Plaintext
9698 * on the wire (the request travels over the trusted
9699 * in-cluster network with a bridge bearer token); encrypted
9700 * under `LQ_AI_BRIDGE_MASTER_KEY` before persistence.
9701 * @example xoxb-...
9702 */
9703 bot_token: string;
9704 /**
9705 * @description Slack user id of the bot user.
9706 * @example U99BOT
9707 */
9708 bot_user_id: string;
9709 /**
9710 * @description Slack user id of the operator who completed install (audit only).
9711 * @example U11INSTALLER
9712 */
9713 installer_slack_user_id: string;
9714 /**
9715 * @description Comma-separated scope list Slack returned.
9716 * @example commands,chat:write
9717 */
9718 scope: string;
9719 };
9720 /**
9721 * @description Request body for `POST /api/v1/integrations/teams/tenants`
9722 * (M3-D3). Shape matches what `teams-bridge/app/oauth.py`
9723 * constructs from the Microsoft id_token claims (`tid`, `oid`)
9724 * + a best-effort Microsoft Graph `/organization` display-name
9725 * lookup.
9726 */
9727 TeamsTenantCreate: {
9728 /**
9729 * @description Microsoft tenant id (`tid` claim — the M365 directory GUID).
9730 * @example 00000000-0000-0000-0000-aaaaaaaaaaaa
9731 */
9732 tenant_id: string;
9733 /**
9734 * @description Tenant display name at install time. Best-effort from
9735 * Microsoft Graph `/organization`; falls back to the
9736 * tenant_id if Graph errors.
9737 * @example Acme Legal LLP
9738 */
9739 tenant_name: string;
9740 /**
9741 * @description M365 `oid` claim of the admin who completed consent.
9742 * Audit only — does not grant LQ.AI permissions.
9743 * @example 00000000-0000-0000-0000-111111111111
9744 */
9745 installer_oid: string;
9746 };
9747 /**
9748 * @description Persisted-tenant response for `POST
9749 * /api/v1/integrations/teams/tenants`. Mirrors
9750 * `SlackWorkspaceResponse` minus the per-tenant bot fields
9751 * (Teams uses app-level credentials).
9752 */
9753 TeamsTenantResponse: {
9754 /**
9755 * Format: uuid
9756 * @description api-side tenant row id.
9757 */
9758 id: string;
9759 /** @example 00000000-0000-0000-0000-aaaaaaaaaaaa */
9760 tenant_id: string;
9761 /** @example Acme Legal LLP */
9762 tenant_name: string;
9763 /** @example 00000000-0000-0000-0000-111111111111 */
9764 installer_oid: string;
9765 /**
9766 * Format: date-time
9767 * @description Original install timestamp. NOT moved by upsert.
9768 */
9769 installed_at: string;
9770 };
9771 /**
9772 * @description One live Slack workspace row in the admin intake-bridges list
9773 * (M3-D4). The wire shape mirrors the model row minus the bot
9774 * token ciphertext (which the admin UI has no business seeing).
9775 */
9776 SlackWorkspaceSummary: {
9777 /** Format: uuid */
9778 id: string;
9779 team_id: string;
9780 team_name: string;
9781 installer_slack_user_id: string;
9782 /** Format: date-time */
9783 installed_at: string;
9784 };
9785 /**
9786 * @description One live Microsoft 365 tenant row in the admin intake-bridges
9787 * list (M3-D4). Mirrors the model row.
9788 */
9789 TeamsTenantSummary: {
9790 /** Format: uuid */
9791 id: string;
9792 tenant_id: string;
9793 tenant_name: string;
9794 installer_oid: string;
9795 /** Format: date-time */
9796 installed_at: string;
9797 };
9798 /**
9799 * @description Section-split response for `GET /api/v1/admin/intake-bridges`.
9800 * Separate sections (rather than a single polymorphic list) so
9801 * the SvelteKit admin page renders two distinct sections without
9802 * client-side discriminator-key gymnastics.
9803 */
9804 IntakeBridgesList: {
9805 slack_workspaces: components["schemas"]["SlackWorkspaceSummary"][];
9806 teams_tenants: components["schemas"]["TeamsTenantSummary"][];
9807 };
9808 /**
9809 * @description Persisted-workspace response for `POST
9810 * /api/v1/integrations/slack/workspaces`. Bot token is
9811 * deliberately omitted — neither the plaintext nor the
9812 * ciphertext is echoed back to the bridge.
9813 */
9814 SlackWorkspaceResponse: {
9815 /**
9816 * Format: uuid
9817 * @description api-side workspace row id.
9818 */
9819 id: string;
9820 /** @example T01234567 */
9821 team_id: string;
9822 /** @example Acme Legal */
9823 team_name: string;
9824 /** @example U99BOT */
9825 bot_user_id: string;
9826 /** @example U11INSTALLER */
9827 installer_slack_user_id: string;
9828 /** @example commands,chat:write */
9829 scope: string;
9830 /**
9831 * Format: date-time
9832 * @description Original install timestamp. NOT moved by upsert.
9833 */
9834 installed_at: string;
9835 };
9836 /**
9837 * @description Response payload for `GET /api/v1/word-addin/version` (M3-B8).
9838 * Consumed by the task pane on mount to decide whether the
9839 * installed add-in version is compatible with this deployment.
9840 */
9841 WordAddinVersionResponse: {
9842 /**
9843 * @description LQ.AI deployment version (the api package `__version__`).
9844 * Informational — the add-in surfaces it in the "Update
9845 * needed" overlay so users can quote it to support.
9846 * @example 0.3.0
9847 */
9848 deployment_version: string;
9849 /**
9850 * @description Lowest add-in version (semver string) this deployment
9851 * accepts. The task pane refuses to render features when
9852 * its bundled version is lower.
9853 * @example 0.3.0
9854 */
9855 addin_min_compatible_version: string;
9856 /**
9857 * @description Highest add-in version this deployment recognizes. Bundles
9858 * newer than this still load (forward compatibility is
9859 * best-effort) but the add-in surfaces a soft warning so the
9860 * operator knows to update the deployment.
9861 * @example 0.3.99
9862 */
9863 addin_max_compatible_version: string;
9864 /**
9865 * Format: uri
9866 * @description Canonical URL of the task pane bundle's HTML entry point.
9867 * @example https://lq.acme.example/word-addin/taskpane.html
9868 */
9869 taskpane_bundle_url: string;
9870 /**
9871 * @description Optional SHA-256 hash of the deployed task pane bundle JS.
9872 * M3-B8 ships nullable; M3-B7 signing CI populates the value.
9873 * Null means "don't enforce" — not an error.
9874 * @example null
9875 */
9876 taskpane_bundle_hash?: string | null;
9877 };
9878 /**
9879 * @description One acceptable alternative to a position's standard language.
9880 * Ranked 1-based (1 = preferred fallback). Stored as JSONB on
9881 * ``playbook_positions.fallback_tiers`` (M3-A1).
9882 */
9883 FallbackTier: {
9884 rank: number;
9885 description: string;
9886 language: string;
9887 };
9888 /**
9889 * @description One issue in a playbook — the org's standard + fallbacks for a
9890 * clause. Mirrors the ``Position`` shape in PRD §3.7.
9891 */
9892 Position: {
9893 /** Format: uuid */
9894 id: string;
9895 issue: string;
9896 description?: string;
9897 standard_language: string;
9898 fallback_tiers?: components["schemas"]["FallbackTier"][];
9899 redline_strategy?: string;
9900 /** @enum {string} */
9901 severity_if_missing: "critical" | "high" | "medium" | "low";
9902 detection_keywords?: string[];
9903 detection_examples?: string[];
9904 position_order?: number;
9905 };
9906 /**
9907 * @description Full playbook — header plus ordered positions. Mirrors PRD §3.7.
9908 * ``GET /api/v1/playbooks`` returns this shape with ``positions``
9909 * empty; ``GET /api/v1/playbooks/{id}`` returns it with the full
9910 * position list inlined.
9911 */
9912 Playbook: {
9913 /** Format: uuid */
9914 id: string;
9915 name: string;
9916 contract_type: string;
9917 description?: string;
9918 version?: string;
9919 /** Format: uuid */
9920 created_by?: string | null;
9921 /** Format: date-time */
9922 created_at: string;
9923 /** Format: date-time */
9924 updated_at: string;
9925 positions?: components["schemas"]["Position"][];
9926 };
9927 /**
9928 * @description Request shape for a single position when creating or updating a
9929 * playbook (M3-A6). Identical to ``Position`` minus the server-
9930 * assigned ``id`` (the server mints UUIDs at insert time).
9931 */
9932 PositionCreate: {
9933 issue: string;
9934 description?: string;
9935 standard_language: string;
9936 fallback_tiers?: components["schemas"]["FallbackTier"][];
9937 redline_strategy?: string;
9938 /** @enum {string} */
9939 severity_if_missing: "critical" | "high" | "medium" | "low";
9940 detection_keywords?: string[];
9941 detection_examples?: string[];
9942 position_order?: number;
9943 };
9944 /**
9945 * @description Request shape for ``POST /api/v1/playbooks`` (M3-A6). The server
9946 * sets ``created_by`` to the caller's id unconditionally; there is
9947 * no path to mint a built-in (``created_by IS NULL``) via the HTTP
9948 * surface (built-ins ship via seed migration only).
9949 */
9950 PlaybookCreate: {
9951 name: string;
9952 contract_type: string;
9953 description?: string;
9954 version?: string;
9955 positions?: components["schemas"]["PositionCreate"][];
9956 };
9957 /**
9958 * @description Request shape for ``PATCH /api/v1/playbooks/{id}`` (M3-A6). All
9959 * fields optional; a missing field is "leave alone." If
9960 * ``positions`` is supplied, the server **atomically replaces**
9961 * the entire positions list. To leave positions alone, omit the
9962 * field; to clear them, send ``positions: []``.
9963 */
9964 PlaybookUpdate: {
9965 name?: string;
9966 contract_type?: string;
9967 description?: string;
9968 version?: string;
9969 positions?: components["schemas"]["PositionCreate"][] | null;
9970 };
9971 /**
9972 * @description Request shape for ``POST /api/v1/playbooks/easy`` (M3-A6). The
9973 * document corpus the wizard's Step 1 collected, plus the
9974 * contract family and an optional caller-supplied name.
9975 */
9976 EasyPlaybookGenerationCreate: {
9977 document_ids: string[];
9978 /**
9979 * @description The contract family the playbook targets ("NDA",
9980 * "MSA-SaaS", "DPA", etc.). Free-form; passed to the
9981 * extractor + assembly LLM calls as a hint.
9982 */
9983 contract_type: string;
9984 /**
9985 * @description Playbook name. Falls back to "Generated {contract_type}
9986 * Playbook" if omitted.
9987 */
9988 name?: string | null;
9989 /**
9990 * @description Reserved for a future ephemeral-upload mode. Currently
9991 * always true; uploaded documents persist to the user's
9992 * library per M3-A6 §3.3.
9993 * @default true
9994 */
9995 persist_documents_after_generation: boolean;
9996 };
9997 /**
9998 * @description One row from the ``easy_playbook_generations`` table. Returned
9999 * by ``POST /api/v1/playbooks/easy`` (at status ``pending``) and
10000 * by ``GET /api/v1/playbooks/easy/{id}`` (the wizard's poll
10001 * target). ``draft_playbook`` is populated only on
10002 * ``status='completed'`` and carries the assembled
10003 * ``PlaybookCreate`` shape for the Step 3 inline editor.
10004 */
10005 EasyPlaybookGeneration: {
10006 /** Format: uuid */
10007 id: string;
10008 /** Format: uuid */
10009 user_id?: string | null;
10010 contract_type: string;
10011 /** @enum {string} */
10012 status: "pending" | "running" | "completed" | "error";
10013 document_ids: string[];
10014 /**
10015 * @description The assembled ``PlaybookCreate`` shape. ``null`` until the
10016 * worker reaches ``status='completed'``.
10017 */
10018 draft_playbook?: {
10019 [key: string]: unknown;
10020 } | null;
10021 error_message?: string | null;
10022 /** Format: date-time */
10023 created_at: string;
10024 /** Format: date-time */
10025 started_at?: string | null;
10026 /** Format: date-time */
10027 completed_at?: string | null;
10028 };
10029 /**
10030 * @description One execution of a playbook against a target document.
10031 * Status lifecycle: ``pending → running → completed | error``.
10032 * ``results`` is populated on ``completed``; ``error`` is populated
10033 * on ``error``. ``completed_at`` is non-null in either terminal state.
10034 */
10035 PlaybookExecution: {
10036 /** Format: uuid */
10037 id: string;
10038 /** Format: uuid */
10039 playbook_id: string;
10040 /** Format: uuid */
10041 target_document_id: string;
10042 /** Format: uuid */
10043 user_id?: string | null;
10044 /** Format: uuid */
10045 project_id?: string | null;
10046 /** @enum {string} */
10047 status: "pending" | "running" | "completed" | "error";
10048 /**
10049 * @description Per-position outcomes + summary. Shape is versioned via
10050 * ``schema_version`` (currently ``m3-a2-v1``); see the
10051 * M3-A2 executor module for the canonical structure.
10052 */
10053 results?: {
10054 [key: string]: unknown;
10055 } | null;
10056 error?: string | null;
10057 /** Format: date-time */
10058 created_at: string;
10059 /** Format: date-time */
10060 completed_at?: string | null;
10061 };
10062 /**
10063 * @description Request body for ``POST /api/v1/tabular/preview-cost``. Either
10064 * ``skill_name`` or ``columns`` must be supplied (not both).
10065 */
10066 TabularPreviewCostRequest: {
10067 document_ids: string[];
10068 /** @description Name of a registered ``output_format: table`` skill. */
10069 skill_name?: string | null;
10070 /** @description Ad-hoc column spec (alternative to ``skill_name``). */
10071 columns?: components["schemas"]["ColumnSpec"][] | null;
10072 };
10073 TabularPreviewCostResponse: {
10074 /** @description ``len(document_ids) * len(columns)``. */
10075 cells_count: number;
10076 /** @description Per-cell token average x cells_count. */
10077 estimated_tokens: number;
10078 /**
10079 * @description Per-cell rolling-average cost x cells_count, serialized as
10080 * a JSON string to preserve decimal precision.
10081 */
10082 estimated_cost_usd: string;
10083 /**
10084 * @description Map of tier label (``tier_1`` / ``tier_2`` / ... or
10085 * ``default``) to cell count routed at that tier. Columns
10086 * without an explicit ``minimum_inference_tier`` count in
10087 * the ``default`` bucket.
10088 */
10089 per_tier_breakdown: {
10090 [key: string]: number;
10091 };
10092 /**
10093 * @description Number of cells that will run ensemble Citation-Engine
10094 * verification (``len(document_ids) * ensemble-column count``).
10095 * ``0`` when no column is ensemble-verified.
10096 */
10097 ensemble_cells_count?: number;
10098 /**
10099 * @description The ensemble judge-call cost included in
10100 * ``estimated_cost_usd`` (= ``n_judges * per-judge-cost *
10101 * ensemble_cells_count``), serialized as a JSON string to
10102 * preserve decimal precision. ``"0"`` when no column is
10103 * ensemble-verified. Note that ``estimated_cost_usd`` is the
10104 * TOTAL (base extraction + this premium); ``estimated_tokens``
10105 * is extraction-only and excludes judge tokens.
10106 */
10107 ensemble_premium_usd?: string;
10108 };
10109 /**
10110 * @description Request body for ``POST /api/v1/tabular/execute``. Either
10111 * ``skill_name`` or ``columns`` must be supplied (not both).
10112 * ``confirmed_cost_usd`` echoes the preview value so the row
10113 * carries an audit trail of the operator confirming a specific
10114 * cost ceiling.
10115 */
10116 TabularExecutionCreate: {
10117 document_ids: string[];
10118 skill_name?: string | null;
10119 columns?: components["schemas"]["ColumnSpec"][] | null;
10120 /**
10121 * @description Operator-confirmed cost from the preview endpoint. Persisted
10122 * to ``tabular_executions.cost_estimate_usd``.
10123 */
10124 confirmed_cost_usd?: string | null;
10125 };
10126 /**
10127 * @description One row from the ``tabular_executions`` table. Lifecycle:
10128 * ``pending → running → completed | failed | cancelled``.
10129 * ``results`` is populated by the aggregate node on ``completed``;
10130 * ``error_text`` is populated on ``failed``. Soft-deleted rows
10131 * (``deleted_at`` non-null) are invisible to list / detail
10132 * endpoints.
10133 */
10134 TabularExecution: {
10135 /** Format: uuid */
10136 id: string;
10137 /** Format: uuid */
10138 user_id?: string | null;
10139 /**
10140 * Format: uuid
10141 * @description Non-null on bulk-op sibling rows (Phase C prep doc Decision
10142 * C-9). Bulk ops spawn siblings rather than mutating the
10143 * original grid, preserving auditability.
10144 */
10145 parent_execution_id?: string | null;
10146 /**
10147 * @description Source skill name; ``null`` for ad-hoc executions where the
10148 * operator typed columns directly in the wizard.
10149 */
10150 skill_name?: string | null;
10151 /** @enum {string} */
10152 status: "pending" | "running" | "completed" | "failed" | "cancelled";
10153 document_ids: string[];
10154 /**
10155 * @description Per-document display names (operator-uploaded filenames),
10156 * parallel to ``document_ids`` in selection order. Assembled on
10157 * the response by ``_to_response``; not a stored column.
10158 */
10159 document_names: string[];
10160 columns: components["schemas"]["ColumnSpec"][];
10161 /**
10162 * @description Assembled grid shape with rows + per-cell results. Shape is
10163 * versioned via ``schema_version`` (currently ``m3-c2-v1``).
10164 *
10165 * Each cell result also carries ``verification_method``
10166 * (string, nullable) — the per-cell ensemble Citation-Engine
10167 * verification outcome (``ensemble_strict`` /
10168 * ``ensemble_majority``), or ``null`` when the cell's column is
10169 * not ensemble-verified or verification did not confirm support.
10170 *
10171 * Each cell carries a ``citations`` array. A tabular cell
10172 * ``Citation`` is distinct from the chat ``Citation`` schema; it
10173 * has: ``citation_id`` (uuid; deterministic display-only id —
10174 * DE-309), ``document_id`` (uuid; the source ``documents.id``),
10175 * ``chunk_id`` (uuid, nullable; the cited ``document_chunks.id``),
10176 * and ``confidence`` (one of ``high|medium|low|failed``). Each
10177 * citation additionally carries ``verification_method`` (string,
10178 * nullable) — the Citation-Engine verification method
10179 * (``ensemble_strict`` / ``ensemble_majority``), or ``null`` when
10180 * the cell's column is not ensemble-verified or verification did
10181 * not confirm support. It is mirrored from the cell-level value.
10182 *
10183 * On ``GET /api/v1/tabular/executions/{id}`` (only) each citation
10184 * is additionally enriched at read time so the frontend can open
10185 * the cited source in its doc panel (same UX as chat citations):
10186 *
10187 * - ``source_file_id`` (uuid, nullable): the source document's
10188 * ``documents.file_id`` — the ``files.id`` the doc panel keys
10189 * off. ``null`` when the backing chunk row is missing/stale.
10190 * - ``source_page`` (integer, nullable): the cited chunk's
10191 * ``document_chunks.page_start`` (nullable — best-effort page
10192 * assignment).
10193 * - ``source_text`` (string, nullable): the cited chunk's full
10194 * ``document_chunks.content`` (the frontend locates/highlights
10195 * the cited span within it).
10196 *
10197 * These three fields are resolved via two batched ``IN`` queries
10198 * (chunks, then documents) — no N+1 — and are ``null`` on the
10199 * list/export paths, which do not enrich.
10200 */
10201 results?: {
10202 [key: string]: unknown;
10203 } | null;
10204 cost_estimate_usd?: string | null;
10205 cost_actual_usd?: string | null;
10206 error_text?: string | null;
10207 /** Format: date-time */
10208 created_at: string;
10209 /** Format: date-time */
10210 started_at?: string | null;
10211 /** Format: date-time */
10212 completed_at?: string | null;
10213 };
10214 /**
10215 * @description Compact projection used by the list endpoint. Drops the
10216 * (potentially large) ``results`` payload — operators fetch the
10217 * full execution row when they open one.
10218 */
10219 TabularExecutionSummary: {
10220 /** Format: uuid */
10221 id: string;
10222 /** Format: uuid */
10223 user_id?: string | null;
10224 /** Format: uuid */
10225 parent_execution_id?: string | null;
10226 skill_name?: string | null;
10227 /** @enum {string} */
10228 status: "pending" | "running" | "completed" | "failed" | "cancelled";
10229 document_count: number;
10230 column_count: number;
10231 cost_estimate_usd?: string | null;
10232 cost_actual_usd?: string | null;
10233 /** Format: date-time */
10234 created_at: string;
10235 /** Format: date-time */
10236 completed_at?: string | null;
10237 };
10238 AdminUserRow: {
10239 /** Format: uuid */
10240 id: string;
10241 /** Format: email */
10242 email: string;
10243 display_name?: string | null;
10244 /** @enum {string} */
10245 role: "admin" | "member" | "viewer";
10246 is_admin: boolean;
10247 mfa_enabled: boolean;
10248 must_change_password: boolean;
10249 /** Format: date-time */
10250 created_at: string;
10251 /** Format: date-time */
10252 last_login_at?: string | null;
10253 /** Format: date-time */
10254 deletion_scheduled_at?: string | null;
10255 };
10256 /**
10257 * @description Read-only view of an ``autonomous_findings`` row — one analysis
10258 * finding emitted by a run via the ``emit_finding`` chokepoint.
10259 * ``content`` is the finding body (the LLM's ``summary``).
10260 * ``severity`` is LLM-emitted free text (no CHECK; ``info`` |
10261 * ``warn`` | ``critical`` are the intended values).
10262 */
10263 AutonomousFindingRead: {
10264 /** Format: uuid */
10265 id: string;
10266 /** Format: uuid */
10267 session_id: string;
10268 severity: string;
10269 title: string;
10270 content: string;
10271 /** Format: date-time */
10272 created_at: string;
10273 };
10274 /**
10275 * @description Paginated list of a session's findings, in stable
10276 * ``created_at ASC, id ASC`` order — one run's rows typically
10277 * share ``created_at`` (transaction-stable ``now()``); ``id`` is
10278 * the pagination tiebreaker. Repeatable, not a guaranteed
10279 * emission sequence.
10280 */
10281 AutonomousFindingListResponse: {
10282 findings: components["schemas"]["AutonomousFindingRead"][];
10283 total_count: number;
10284 limit: number;
10285 offset: number;
10286 };
10287 /**
10288 * @description Read-only view of an ``autonomous_artifacts`` row — a reference to
10289 * one document-grade artifact (a markdown memo) an opted-in run
10290 * persisted into its target knowledge base via the ``emit_artifact``
10291 * chokepoint. ``name`` and ``mime`` are LLM-emitted free text (no
10292 * CHECK; the ``severity`` precedent).
10293 */
10294 AutonomousArtifactRead: {
10295 /** Format: uuid */
10296 id: string;
10297 name: string;
10298 mime: string;
10299 size_bytes: number;
10300 /**
10301 * Format: uuid
10302 * @description The backing ``files`` row. The FK is ``ON DELETE SET NULL`` —
10303 * null means the file was later hard-deleted; the name/size
10304 * metadata here survives. The KB document itself outlives the
10305 * session (deleting the session removes only this reference).
10306 */
10307 file_id?: string | null;
10308 /**
10309 * Format: uuid
10310 * @description NOT a column on ``autonomous_artifacts`` — enriched at read
10311 * time via the unique ``documents.file_id`` (1:1) so a client
10312 * can deep-link the KB document. Null when ``file_id`` is null
10313 * or no ``documents`` row exists for the file.
10314 */
10315 document_id?: string | null;
10316 /** Format: date-time */
10317 created_at: string;
10318 };
10319 /**
10320 * @description Paginated list of a session's artifact references, in the same
10321 * stable ``created_at ASC, id ASC`` order as the findings list —
10322 * repeatable, not a guaranteed emission sequence.
10323 */
10324 AutonomousArtifactListResponse: {
10325 artifacts: components["schemas"]["AutonomousArtifactRead"][];
10326 total_count: number;
10327 limit: number;
10328 offset: number;
10329 };
10330 /**
10331 * @description Read-only view of an ``autonomous_memory`` row. Returned by the
10332 * list, keep, dismiss, and delete endpoints.
10333 */
10334 AutonomousMemoryRead: {
10335 /** Format: uuid */
10336 id: string;
10337 /** Format: uuid */
10338 user_id: string;
10339 /** @enum {string} */
10340 state: "proposed" | "kept" | "dismissed";
10341 category: string;
10342 content: string;
10343 /** Format: uuid */
10344 source_session_id?: string | null;
10345 /** Format: date-time */
10346 kept_at?: string | null;
10347 /** Format: date-time */
10348 deleted_at?: string | null;
10349 /** Format: date-time */
10350 created_at: string;
10351 /** Format: date-time */
10352 updated_at: string;
10353 };
10354 /** @description Paginated list of autonomous memory entries (non-deleted, newest first). */
10355 AutonomousMemoryListResponse: {
10356 entries: components["schemas"]["AutonomousMemoryRead"][];
10357 total_count: number;
10358 limit: number;
10359 offset: number;
10360 };
10361 /**
10362 * @description Optional request body for ``POST /autonomous/memory/{id}/keep``.
10363 * If ``content`` is provided, the memory entry's text is overwritten
10364 * on keep (edit-on-keep).
10365 */
10366 MemoryKeepRequest: {
10367 content?: string | null;
10368 };
10369 /**
10370 * @description Read-only view of a ``precedent_entries`` row. Returned by the
10371 * list, dismiss endpoints.
10372 */
10373 PrecedentEntryRead: {
10374 /** Format: uuid */
10375 id: string;
10376 /** Format: uuid */
10377 user_id: string;
10378 pattern_kind: string;
10379 summary: string;
10380 observed_count: number;
10381 /** Format: uuid */
10382 source_session_id?: string | null;
10383 /** Format: date-time */
10384 dismissed_at?: string | null;
10385 /** Format: date-time */
10386 created_at: string;
10387 /** Format: date-time */
10388 updated_at: string;
10389 };
10390 /** @description Paginated list of precedent entries (non-dismissed, newest first). */
10391 PrecedentEntryListResponse: {
10392 entries: components["schemas"]["PrecedentEntryRead"][];
10393 total_count: number;
10394 limit: number;
10395 offset: number;
10396 };
10397 /**
10398 * @description Request body for ``POST /autonomous/precedents/{id}/promote``.
10399 * ``project_id`` is the target Project; the caller must own it.
10400 */
10401 PromotePrecedentRequest: {
10402 /** Format: uuid */
10403 project_id: string;
10404 };
10405 /**
10406 * @description Read-only view of a ``project_context_proposals`` row — a proposal
10407 * to promote a precedent into a Project's context document. Only the
10408 * user accepting a proposal writes ``projects.context_md`` (ADR 0013 D5).
10409 */
10410 ProjectContextProposalRead: {
10411 /** Format: uuid */
10412 id: string;
10413 /** Format: uuid */
10414 user_id: string;
10415 /** Format: uuid */
10416 precedent_id: string;
10417 /** Format: uuid */
10418 project_id: string;
10419 suggested_md: string;
10420 /** @enum {string} */
10421 state: "proposed" | "accepted" | "rejected";
10422 /** Format: date-time */
10423 accepted_at?: string | null;
10424 /** Format: date-time */
10425 rejected_at?: string | null;
10426 /** Format: date-time */
10427 created_at: string;
10428 /** Format: date-time */
10429 updated_at: string;
10430 };
10431 /** @description Paginated list of project-context proposals (newest first). */
10432 ProjectContextProposalListResponse: {
10433 proposals: components["schemas"]["ProjectContextProposalRead"][];
10434 total_count: number;
10435 limit: number;
10436 offset: number;
10437 };
10438 /**
10439 * @description Read-only view of an ``autonomous_schedules`` row — a cron-triggered
10440 * run definition.
10441 */
10442 AutonomousScheduleRead: {
10443 /** Format: uuid */
10444 id: string;
10445 /** Format: uuid */
10446 user_id: string;
10447 /** Format: uuid */
10448 project_id?: string | null;
10449 name?: string | null;
10450 cron_expr: string;
10451 /** Format: uuid */
10452 playbook_id?: string | null;
10453 skill_ref?: string | null;
10454 /** Format: uuid */
10455 target_kb_id?: string | null;
10456 enabled: boolean;
10457 /**
10458 * @description Opt-in document-grade artifact emission (Donna #8) for the
10459 * schedule's sessions; default off so existing automations are
10460 * unchanged.
10461 */
10462 emit_artifacts: boolean;
10463 max_cost_usd?: string | null;
10464 /** Format: date-time */
10465 last_run_at?: string | null;
10466 /** Format: date-time */
10467 next_run_at?: string | null;
10468 /** Format: date-time */
10469 deleted_at?: string | null;
10470 /** Format: date-time */
10471 created_at: string;
10472 /** Format: date-time */
10473 updated_at: string;
10474 };
10475 /**
10476 * @description Request body for ``POST /autonomous/schedules``. ``cron_expr`` is a
10477 * five-field cron string (minute hour day-of-month month day-of-week)
10478 * supporting ``*``, lists, ranges, and steps; invalid expressions
10479 * return 422.
10480 */
10481 AutonomousScheduleCreate: {
10482 cron_expr: string;
10483 name?: string | null;
10484 /** Format: uuid */
10485 playbook_id?: string | null;
10486 skill_ref?: string | null;
10487 /** Format: uuid */
10488 target_kb_id?: string | null;
10489 /** Format: uuid */
10490 project_id?: string | null;
10491 /** @default true */
10492 enabled: boolean;
10493 /**
10494 * @description Opt-in document-grade artifact emission (Donna #8) for the
10495 * schedule's sessions; default off so existing automations are
10496 * unchanged.
10497 * @default false
10498 */
10499 emit_artifacts: boolean;
10500 max_cost_usd?: string | null;
10501 };
10502 /**
10503 * @description Request body for ``PATCH /autonomous/schedules/{id}``. All fields
10504 * optional. Changing ``cron_expr`` re-validates (422) and recomputes
10505 * ``next_run_at``. The matter (``project_id``) may be reassigned; an
10506 * explicit ``null`` unassigns it, and a non-null ``project_id`` the
10507 * caller does not own returns 404 (id-probing-safe).
10508 */
10509 AutonomousScheduleUpdate: {
10510 name?: string | null;
10511 cron_expr?: string | null;
10512 enabled?: boolean | null;
10513 /**
10514 * @description Toggle opt-in document-grade artifact emission (Donna #8)
10515 * for the schedule's future sessions; omitted/null = unchanged.
10516 */
10517 emit_artifacts?: boolean | null;
10518 /** Format: uuid */
10519 playbook_id?: string | null;
10520 skill_ref?: string | null;
10521 /** Format: uuid */
10522 target_kb_id?: string | null;
10523 /** Format: uuid */
10524 project_id?: string | null;
10525 max_cost_usd?: string | null;
10526 };
10527 /**
10528 * @description Request body for ``POST /autonomous/run-now``. Spawns one
10529 * ``trigger_kind='manual'`` session. Exactly one of ``playbook_id``
10530 * / ``skill_ref`` must be set (zero or both → 422). ``target_kb_id``
10531 * / ``project_id`` are optional scope. ``max_cost_usd`` is the
10532 * per-run cap (NULL → fall back to the config default). A manual
10533 * run has no schedule/watch row to inherit ``emit_artifacts`` from,
10534 * so this body IS the opt-in source.
10535 */
10536 AutonomousManualRunRequest: {
10537 /** Format: uuid */
10538 playbook_id?: string | null;
10539 skill_ref?: string | null;
10540 /** Format: uuid */
10541 target_kb_id?: string | null;
10542 /** Format: uuid */
10543 project_id?: string | null;
10544 max_cost_usd?: string | null;
10545 /**
10546 * @description Opt-in document-grade artifact emission (Donna #8) for this
10547 * one-off run; default off so existing callers are unchanged.
10548 * @default false
10549 */
10550 emit_artifacts: boolean;
10551 };
10552 /** @description Paginated list of autonomous schedules (newest first). */
10553 AutonomousScheduleListResponse: {
10554 schedules: components["schemas"]["AutonomousScheduleRead"][];
10555 total_count: number;
10556 limit: number;
10557 offset: number;
10558 };
10559 /**
10560 * @description Read-only view of an ``autonomous_watches`` row — a KB-arrival-
10561 * triggered run definition. When a file is attached to
10562 * ``knowledge_base_id``, an autonomous session spawns.
10563 */
10564 AutonomousWatchRead: {
10565 /** Format: uuid */
10566 id: string;
10567 /** Format: uuid */
10568 user_id: string;
10569 /** Format: uuid */
10570 project_id?: string | null;
10571 /** Format: uuid */
10572 knowledge_base_id: string;
10573 /** Format: uuid */
10574 playbook_id?: string | null;
10575 skill_ref?: string | null;
10576 enabled: boolean;
10577 /**
10578 * @description Opt-in document-grade artifact emission (Donna #8) for the
10579 * watch's sessions; default off so existing automations are
10580 * unchanged.
10581 */
10582 emit_artifacts: boolean;
10583 max_cost_usd?: string | null;
10584 /** Format: date-time */
10585 deleted_at?: string | null;
10586 /** Format: date-time */
10587 created_at: string;
10588 /** Format: date-time */
10589 updated_at: string;
10590 };
10591 /**
10592 * @description Request body for ``POST /autonomous/watches``. ``knowledge_base_id``
10593 * is required and must be owned by the caller (404 otherwise; KB-sharing
10594 * is out of scope). The target (``playbook_id`` / ``skill_ref``) and
10595 * ``project_id`` are optional; ``enabled`` defaults to true.
10596 */
10597 AutonomousWatchCreate: {
10598 /** Format: uuid */
10599 knowledge_base_id: string;
10600 /** Format: uuid */
10601 playbook_id?: string | null;
10602 skill_ref?: string | null;
10603 /** Format: uuid */
10604 project_id?: string | null;
10605 /** @default true */
10606 enabled: boolean;
10607 /**
10608 * @description Opt-in document-grade artifact emission (Donna #8) for the
10609 * watch's sessions; default off so existing automations are
10610 * unchanged.
10611 * @default false
10612 */
10613 emit_artifacts: boolean;
10614 max_cost_usd?: string | null;
10615 };
10616 /**
10617 * @description Request body for ``PATCH /autonomous/watches/{id}``. All fields
10618 * optional. The watch's ``knowledge_base_id`` is immutable (not
10619 * present here) — a watch is bound to its KB. The matter
10620 * (``project_id``) may be reassigned; an explicit ``null`` unassigns
10621 * it, and a non-null ``project_id`` the caller does not own returns
10622 * 404 (id-probing-safe).
10623 */
10624 AutonomousWatchUpdate: {
10625 enabled?: boolean | null;
10626 /**
10627 * @description Toggle opt-in document-grade artifact emission (Donna #8)
10628 * for the watch's future sessions; omitted/null = unchanged.
10629 */
10630 emit_artifacts?: boolean | null;
10631 /** Format: uuid */
10632 playbook_id?: string | null;
10633 skill_ref?: string | null;
10634 /** Format: uuid */
10635 project_id?: string | null;
10636 max_cost_usd?: string | null;
10637 };
10638 /** @description Paginated list of autonomous watches (newest first). */
10639 AutonomousWatchListResponse: {
10640 watches: components["schemas"]["AutonomousWatchRead"][];
10641 total_count: number;
10642 limit: number;
10643 offset: number;
10644 };
10645 /**
10646 * @description Read-only view of an ``autonomous_notifications`` row. Written by
10647 * the ``notify`` chokepoint handler. ``read_at`` IS NULL = unread;
10648 * marking read is the dismiss action. ``channel`` is one of
10649 * ``in_app`` / ``email`` / ``webhook`` (``webhook`` reserved).
10650 * ``body``/``payload`` carry counts/IDs + a receipt link — never raw
10651 * entity values. A run-completion notification's ``payload`` carries
10652 * ``finding_count`` and ``artifact_count`` (``artifact_count`` is 0
10653 * unless the run opted in via ``emit_artifacts``).
10654 */
10655 AutonomousNotificationRead: {
10656 /** Format: uuid */
10657 id: string;
10658 /** Format: uuid */
10659 user_id: string;
10660 /** Format: uuid */
10661 session_id: string;
10662 /** @enum {string} */
10663 channel: "in_app" | "email" | "webhook";
10664 title: string;
10665 body: string;
10666 payload?: {
10667 [key: string]: unknown;
10668 } | null;
10669 /** Format: date-time */
10670 read_at?: string | null;
10671 /** Format: date-time */
10672 created_at: string;
10673 /** Format: date-time */
10674 updated_at: string;
10675 };
10676 /** @description Paginated list of autonomous notifications (newest first). */
10677 AutonomousNotificationListResponse: {
10678 notifications: components["schemas"]["AutonomousNotificationRead"][];
10679 total_count: number;
10680 limit: number;
10681 offset: number;
10682 };
10683 /**
10684 * @description Read-only view of an ``autonomous_sessions`` row. Returned by the
10685 * halt, list, and detail endpoints.
10686 */
10687 AutonomousSessionRead: {
10688 /** Format: uuid */
10689 id: string;
10690 /** Format: uuid */
10691 user_id: string;
10692 /** Format: uuid */
10693 project_id?: string | null;
10694 /** @enum {string} */
10695 trigger_kind: "watch" | "schedule" | "suggestion" | "manual";
10696 /** Format: uuid */
10697 trigger_ref?: string | null;
10698 /** @enum {string} */
10699 current_phase: "intake" | "analysis" | "drafting" | "ethics_review" | "delivery";
10700 /** @enum {string} */
10701 halt_state: "running" | "halt_requested" | "halted" | "paused";
10702 max_cost_usd?: string | null;
10703 cost_total_usd: string;
10704 cost_cap_reached: boolean;
10705 idle_halt_minutes: number;
10706 /** Format: date-time */
10707 last_activity_at: string;
10708 /** @enum {string} */
10709 status: "running" | "completed" | "halted" | "failed";
10710 params?: {
10711 [key: string]: unknown;
10712 };
10713 result?: {
10714 [key: string]: unknown;
10715 } | null;
10716 error?: string | null;
10717 /** Format: date-time */
10718 created_at: string;
10719 /** Format: date-time */
10720 updated_at: string;
10721 /** Format: date-time */
10722 completed_at?: string | null;
10723 };
10724 /** @description Paginated list of autonomous sessions (newest first). */
10725 AutonomousSessionListResponse: {
10726 sessions: components["schemas"]["AutonomousSessionRead"][];
10727 total_count: number;
10728 limit: number;
10729 offset: number;
10730 };
10731 /**
10732 * @description Session detail view with live-reconstructed receipt.
10733 * The receipt is built from audit rows on every request and contains
10734 * phase transitions, tool calls, terminal reason, and session metadata.
10735 * No raw document text or entity values are included.
10736 */
10737 AutonomousSessionDetailResponse: {
10738 session: components["schemas"]["AutonomousSessionRead"];
10739 /**
10740 * @description Audit-derived receipt: session_id, trigger_kind, status,
10741 * halt_state, current_phase, cost_total_usd, max_cost_usd,
10742 * cost_cap_reached, created_at, completed_at,
10743 * phase_transitions (list), tool_calls (list),
10744 * terminal_reason (string | null).
10745 */
10746 receipt: {
10747 [key: string]: unknown;
10748 };
10749 };
10750 AdminUserListResponse: {
10751 users: components["schemas"]["AdminUserRow"][];
10752 total_count: number;
10753 limit: number;
10754 offset: number;
10755 };
10756 LoginRequest: {
10757 /** Format: email */
10758 email: string;
10759 /** Format: password */
10760 password: string;
10761 };
10762 LoginResponse: {
10763 access_token: string;
10764 /** @enum {string} */
10765 token_type: "Bearer";
10766 /** @description Lifetime in seconds */
10767 expires_in: number;
10768 refresh_token?: string;
10769 user: components["schemas"]["User"];
10770 };
10771 TokenResponse: {
10772 /** @description Short-lived JWT access token (~15 min). */
10773 access_token: string;
10774 /**
10775 * @description Refresh token returned on /auth/login and rotated on every
10776 * /auth/refresh per PRD §5.1. The bearer of the most recent
10777 * refresh_token can mint new access tokens; older refresh
10778 * tokens are revoked when rotation happens.
10779 */
10780 refresh_token: string;
10781 /** @enum {string} */
10782 token_type: "Bearer";
10783 /** @description Seconds until the access token expires. */
10784 expires_in: number;
10785 };
10786 MfaChallenge: {
10787 mfa_token: string;
10788 methods: ("totp" | "recovery_code")[];
10789 };
10790 ChangePasswordRequest: {
10791 /**
10792 * Format: password
10793 * @description The user's current password. Required even when the
10794 * `must_change_password` flag is set — a stolen access token
10795 * alone must not be sufficient to rotate credentials.
10796 */
10797 current_password: string;
10798 /**
10799 * Format: password
10800 * @description The replacement password. Must satisfy the deployment's
10801 * password policy (minimum length, etc.) and must differ from
10802 * `current_password`. The first-run admin flow accepts any
10803 * password meeting policy; subsequent rotations may add
10804 * complexity rules.
10805 */
10806 new_password: string;
10807 };
10808 User: {
10809 /** Format: uuid */
10810 id: string;
10811 /** Format: email */
10812 email: string;
10813 display_name?: string | null;
10814 is_admin: boolean;
10815 /**
10816 * @description Wave C — PRD §5.2 RBAC three-role system. ``admin`` has
10817 * full access; ``member`` can mutate owned resources; ``viewer``
10818 * is read-only. Mutating endpoints reject ``viewer`` via the
10819 * ``MutatingUser`` dependency. Kept in sync with ``is_admin``
10820 * (``role='admin'`` iff ``is_admin=true``).
10821 * @default member
10822 * @enum {string}
10823 */
10824 role: "admin" | "member" | "viewer";
10825 mfa_enabled: boolean;
10826 /**
10827 * @description When true, the user must call POST /api/v1/auth/change-password
10828 * before they can use any other authenticated endpoint. Set on
10829 * the auto-created first-run admin (Task B2) and on accounts
10830 * after `reset-admin-password`. Other authenticated endpoints
10831 * return 403 with `error.code = "password_change_required"`
10832 * until this clears.
10833 */
10834 must_change_password: boolean;
10835 /**
10836 * @description Wave A — PRD §3.2 Enhance Prompt reasoning visibility:
10837 * ``always_show`` (reasoning visible by default),
10838 * ``disclosure`` (collapsed behind a toggle; spec default),
10839 * ``on_request`` (hidden until the user opens the skill
10840 * inspector). Modifiable via ``PATCH /users/me/preferences``.
10841 * @default disclosure
10842 * @enum {string}
10843 */
10844 reasoning_visibility: "always_show" | "disclosure" | "on_request";
10845 /**
10846 * @description Wave B v2 — PRD §3.2.1 / frontend spec §4.3. Where Enhance
10847 * Prompt, Skill Creator, KB, and Apply Skill surface:
10848 * ``prominent`` (dashboard cards; default) vs. ``inline``
10849 * (toolbar only for veterans).
10850 * @default prominent
10851 * @enum {string}
10852 */
10853 featured_tools: "prominent" | "inline";
10854 /**
10855 * @description Wave B v2 — PRD §3.2.1 / frontend spec §4.3. Matter workspace
10856 * pane composition (Wave C surfaces): ``three_pane`` (default),
10857 * ``two_pane``, or ``one_pane``.
10858 * @default three_pane
10859 * @enum {string}
10860 */
10861 workspace_layout: "three_pane" | "two_pane" | "one_pane";
10862 /**
10863 * @description Wave B v2 — PRD §3.2.1 / frontend spec §4.3. Ambient trust
10864 * pill format: ``labels`` (full text, e.g. "● self-hosted";
10865 * default) vs. ``dots`` (minimal dot only).
10866 * @default labels
10867 * @enum {string}
10868 */
10869 trust_pills: "labels" | "dots";
10870 /**
10871 * @description Wave B v2 — PRD §3.2.1 / frontend spec §4.3. Per-message
10872 * skill/tier/provider pill row visibility: ``always`` (visible
10873 * by default) vs. ``collapsed`` (hidden until expanded).
10874 * @default always
10875 * @enum {string}
10876 */
10877 provenance_pills: "always" | "collapsed";
10878 /** Format: date-time */
10879 created_at: string;
10880 /** Format: date-time */
10881 last_login_at?: string | null;
10882 /**
10883 * Format: date-time
10884 * @description Non-null while a GDPR Article 17 grace-period deletion is pending (set by POST /users/me/delete, cleared by .../delete/cancel).
10885 */
10886 deletion_scheduled_at?: string | null;
10887 };
10888 /**
10889 * @description All 6 personalization preference fields. Wave A (``reasoning_visibility``)
10890 * per PRD §3.2; Wave B v2 fields per PRD §3.2.1 and frontend spec §4.3;
10891 * ``autonomous_enabled`` per PRD §5 / M4-C2.
10892 */
10893 UserPreferences: {
10894 /**
10895 * @default disclosure
10896 * @enum {string}
10897 */
10898 reasoning_visibility: "always_show" | "disclosure" | "on_request";
10899 /**
10900 * @default prominent
10901 * @enum {string}
10902 */
10903 featured_tools: "prominent" | "inline";
10904 /**
10905 * @default three_pane
10906 * @enum {string}
10907 */
10908 workspace_layout: "three_pane" | "two_pane" | "one_pane";
10909 /**
10910 * @default labels
10911 * @enum {string}
10912 */
10913 trust_pills: "labels" | "dots";
10914 /**
10915 * @default always
10916 * @enum {string}
10917 */
10918 provenance_pills: "always" | "collapsed";
10919 autonomous_enabled: boolean;
10920 };
10921 /**
10922 * @description All fields optional; only supplied keys are updated. Wave B v2 adds
10923 * four personalization fields per PRD §3.2.1 and frontend spec §4.3;
10924 * ``autonomous_enabled`` per PRD §5 / M4-C2.
10925 */
10926 UserPreferencesUpdate: {
10927 /** @enum {string} */
10928 reasoning_visibility?: "always_show" | "disclosure" | "on_request";
10929 /** @enum {string} */
10930 featured_tools?: "prominent" | "inline";
10931 /** @enum {string} */
10932 workspace_layout?: "three_pane" | "two_pane" | "one_pane";
10933 /** @enum {string} */
10934 trust_pills?: "labels" | "dots";
10935 /** @enum {string} */
10936 provenance_pills?: "always" | "collapsed";
10937 autonomous_enabled?: boolean;
10938 };
10939 /**
10940 * @description PATCH body for `/api/v1/users/me`. Caller-scoped self-edit of the
10941 * user's own profile. Currently `display_name` only: when supplied
10942 * it is trimmed and must be non-empty after trimming. At least one
10943 * updatable field must be present (an all-omitted body is a 422).
10944 *
10945 * Email self-service editing is intentionally out of scope here —
10946 * changing the login email pulls in re-verification, MFA, and
10947 * uniqueness concerns and is deferred to a dedicated flow.
10948 */
10949 UserProfileUpdate: {
10950 /**
10951 * @description New display name. Trimmed server-side; must be non-empty after
10952 * trimming. Omit to leave unchanged (but at least one field must
10953 * be present, so an empty body is rejected).
10954 */
10955 display_name?: string;
10956 };
10957 Project: {
10958 /** Format: uuid */
10959 id: string;
10960 name: string;
10961 /**
10962 * @description URL-friendly identifier; unique-per-owner within the active set
10963 * (an archived project's slug can be reused). Generated from
10964 * `name` on create when not supplied; collisions resolve with a
10965 * numeric suffix (`-2`, `-3`, ...).
10966 */
10967 slug: string;
10968 description?: string | null;
10969 /**
10970 * @description Free-form Markdown context document for the matter. Capped at
10971 * 100 KiB (UTF-8 bytes); exceeding the cap returns 422.
10972 */
10973 context_md?: string | null;
10974 /** Format: uuid */
10975 owner_id: string;
10976 /**
10977 * @description When true, every chat in this project is marked privileged in the audit log
10978 * and the routed inference tier is forced to be at least minimum_inference_tier.
10979 * Setting `privileged=true` requires `minimum_inference_tier` to be set;
10980 * attempts to set one without the other return 422 (POST) or 400 (PATCH).
10981 */
10982 privileged: boolean;
10983 /**
10984 * @description When set, requests below this tier are refused
10985 * @enum {integer|null}
10986 */
10987 minimum_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
10988 /** @description Skills attached to this project, ordered by attachment time */
10989 attached_skill_names?: string[];
10990 /** @description Files attached to this project, ordered by attachment time */
10991 attached_file_ids?: string[];
10992 /**
10993 * @description System-managed flag added by migration 0022. When true, this
10994 * project is the per-user try-it sandbox (slug ``__sandbox__``).
10995 * Sandbox projects are excluded from the default ``GET /projects``
10996 * list; pass ``include_sandbox=true`` or ``only_sandbox=true`` to
10997 * surface them. Created by ``POST /projects/sandbox/ensure``.
10998 * @default false
10999 */
11000 is_sandbox: boolean;
11001 /**
11002 * Format: date-time
11003 * @description When set, the project is soft-deleted (archived); excluded from default list
11004 */
11005 archived_at?: string | null;
11006 /** Format: date-time */
11007 created_at: string;
11008 /** Format: date-time */
11009 updated_at: string;
11010 };
11011 ProjectCreate: {
11012 name: string;
11013 /** @description Optional; defaults to slugified `name` with collision suffixes. */
11014 slug?: string;
11015 description?: string;
11016 /** @description Free-form Markdown context document; max 100 KiB. */
11017 context_md?: string;
11018 /** @default false */
11019 privileged: boolean;
11020 /** @enum {integer} */
11021 minimum_inference_tier?: 1 | 2 | 3 | 4 | 5;
11022 };
11023 ProjectUpdate: {
11024 name?: string;
11025 slug?: string;
11026 description?: string;
11027 /** @description Free-form Markdown context document; max 100 KiB. */
11028 context_md?: string;
11029 privileged?: boolean;
11030 /** @enum {integer|null} */
11031 minimum_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11032 /**
11033 * @description When true, archive (soft-delete) the project; when false,
11034 * unarchive a previously-archived project. The dedicated
11035 * `DELETE /api/v1/projects/{id}` endpoint is the destructive
11036 * equivalent of `PATCH {archived: true}`.
11037 */
11038 archived?: boolean;
11039 };
11040 Chat: {
11041 /** Format: uuid */
11042 id: string;
11043 /**
11044 * @description Chat title. Defaults to "New chat"; auto-renamed to the
11045 * first 80 chars of the first user message on first POST
11046 * /messages. Never overwrites a user-set title (one-shot).
11047 */
11048 title: string;
11049 /** Format: uuid */
11050 owner_id: string;
11051 /** Format: uuid */
11052 project_id?: string | null;
11053 /**
11054 * Format: date-time
11055 * @description Soft-delete timestamp. NULL means active.
11056 */
11057 archived_at?: string | null;
11058 /** @description Count of persisted messages in this chat. */
11059 message_count?: number;
11060 /**
11061 * @description Opt-in per-chat "sticky skills" set (issue #207 finding 4).
11062 * Empty means the sticky toggle is off (a new chat never inherits
11063 * stickiness). When non-empty, these skill slugs are auto-applied
11064 * (unioned) to every turn in this chat until cleared. Set via
11065 * `MessageCreate.set_sticky`.
11066 */
11067 sticky_skills?: string[];
11068 /** Format: date-time */
11069 created_at: string;
11070 /** Format: date-time */
11071 updated_at: string;
11072 };
11073 ChatCreate: {
11074 /**
11075 * @description Defaults to "New chat" when omitted. The chat will be
11076 * auto-renamed from the first user message; supplying a
11077 * non-default title here suppresses auto-rename.
11078 */
11079 title?: string;
11080 /** Format: uuid */
11081 project_id?: string | null;
11082 };
11083 /** @description PATCH body for /api/v1/chats/{chat_id}; partial update. */
11084 ChatUpdate: {
11085 title?: string;
11086 /** @description Set true to archive (soft-delete); false to unarchive. */
11087 archived?: boolean;
11088 };
11089 Message: {
11090 /** Format: uuid */
11091 id: string;
11092 /** Format: uuid */
11093 chat_id: string;
11094 /** @enum {string} */
11095 role: "user" | "assistant" | "system" | "tool";
11096 content: string;
11097 /**
11098 * @description C2 / ADR 0007: skills the gateway applied for this message
11099 * exchange. Captured on user messages from the request body
11100 * and on assistant messages from the gateway response.
11101 */
11102 applied_skills?: string[];
11103 /**
11104 * @description Tier the request was routed against (set by gateway). NULL on user messages.
11105 * @enum {integer|null}
11106 */
11107 routed_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11108 /** @description Provider that handled the request (assistant only). */
11109 routed_provider?: string | null;
11110 /** @description Native provider model name (assistant only). */
11111 routed_model?: string | null;
11112 prompt_tokens?: number | null;
11113 completion_tokens?: number | null;
11114 /**
11115 * @description USD cost estimate. The DB stores integer USD micros
11116 * (1e-6 USD); the wire field is the floating-point USD value.
11117 */
11118 cost_estimate?: number | null;
11119 /**
11120 * @description Populated when the assistant message failed mid-stream or
11121 * the gateway raised. Carries the canonical Error code
11122 * (e.g., `provider_unavailable`, `gateway_timeout`).
11123 */
11124 error_code?: string | null;
11125 /** @description M2 populates this; M1 stores []. */
11126 citations?: components["schemas"]["Citation"][];
11127 /** Format: date-time */
11128 created_at: string;
11129 };
11130 MessageCreate: {
11131 content: string;
11132 /**
11133 * @description Model alias (e.g., 'smart', 'fast') or provider-native model name
11134 * @default smart
11135 */
11136 model: string;
11137 /**
11138 * @description When true, response is `text/event-stream` per OpenAI streaming
11139 * convention. When false, response is a single JSON body with the
11140 * assistant message and routing metadata (B5 default).
11141 * @default false
11142 */
11143 stream: boolean;
11144 /**
11145 * @description C2: skill names to attach. The backend forwards these as
11146 * `lq_ai_skills` to the gateway, which fetches each from the
11147 * backend's internal-skills endpoint and assembles the prompt.
11148 */
11149 skills?: string[];
11150 /**
11151 * @description Issue #207 finding 4 — opt-in per-chat "sticky skills" toggle.
11152 * `true` snapshots this turn's applied skills as the chat's sticky
11153 * set (auto-applied to later turns without re-sending); `false`
11154 * clears it; omitted/null leaves it unchanged. Off by default — a
11155 * new chat never inherits stickiness (fail-restrictive).
11156 * @default null
11157 */
11158 set_sticky: boolean | null;
11159 /**
11160 * @description C2: per-skill input bindings, keyed by skill name. Inner
11161 * dict maps input variable names to values. Required inputs
11162 * that the skill's frontmatter declares but the bindings
11163 * don't provide cause a 400 with `code=skill_input_missing`.
11164 *
11165 * Values are plain scalars interpolated into the skill body via
11166 * `{{name}}` substitution (ADR 0006). There is NO `type:"file"`
11167 * binding: passing a file UUID here interpolates the literal
11168 * UUID string, not the file's document text. For per-turn
11169 * document context use the separate `file_ids` channel below —
11170 * `skill_inputs` and `file_ids` are distinct; a `file_id` is
11171 * NOT bindable to a skill file-input via `skill_inputs`.
11172 */
11173 skill_inputs?: {
11174 [key: string]: {
11175 [key: string]: unknown;
11176 };
11177 };
11178 /**
11179 * @description Donna: caller-owned file UUIDs supplying ephemeral,
11180 * per-message document context for this one chat turn.
11181 * Distinct from KB attach (project-scoped, persistent) and
11182 * from `skill_inputs` (scalar skill params — see the note
11183 * above; no `type:"file"` binding is wired). Each id is
11184 * validated server-side to exist and be owned by the caller;
11185 * a foreign, unknown, or soft-deleted id returns 404
11186 * (id-probing-safe — indistinguishable from "not found").
11187 * Validated ids are forwarded to the gateway as `lq_ai_file_ids`
11188 * alongside `lq_ai_skills` and echoed back as `applied_file_ids`
11189 * on the response / SSE `complete` frame. Capped at 16 entries.
11190 * Omitted / empty is back-compatible.
11191 */
11192 file_ids?: string[];
11193 };
11194 /**
11195 * @description Non-streaming response for `POST /api/v1/chats/{chat_id}/messages`.
11196 * The `routed_inference_tier`, `routed_provider`, and `cost_estimate`
11197 * come from the gateway (B4). `applied_skills` lists the skills
11198 * that were assembled into the prompt (C2). After C3 the backend
11199 * also persists both the user and assistant message rows; the
11200 * `message.id` carried here resolves to the persisted assistant
11201 * row.
11202 */
11203 MessagePostResponse: {
11204 message: components["schemas"]["Message"];
11205 /** @description Empty until M2 (citation engine). */
11206 citations: components["schemas"]["Citation"][];
11207 /**
11208 * @description Routed Inference Tier as derived by the gateway (B4)
11209 * @enum {integer|null}
11210 */
11211 routed_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11212 /** @description Provider name that handled the request (B4) */
11213 routed_provider?: string | null;
11214 /** @description USD cost estimate (gateway-side, when rate is configured) */
11215 cost_estimate?: number | null;
11216 /**
11217 * @description C2: skills that were successfully assembled into the prompt
11218 * for this request. Empty when no skills were attached.
11219 */
11220 applied_skills?: string[];
11221 /**
11222 * @description Donna: caller-owned file ids that were validated and
11223 * forwarded to the gateway as `lq_ai_file_ids` for this turn —
11224 * the echo of `MessageCreate.file_ids` (mirrors
11225 * `applied_skills`). Turn-scoped: there is no
11226 * `messages.file_ids` column, so this surfaces only on the send
11227 * response (and the SSE `complete` frame), not on rows read
11228 * back via `GET /chats/{id}/messages`. Empty when none attached.
11229 */
11230 applied_file_ids?: string[];
11231 };
11232 /**
11233 * @description Frames emitted on the SSE stream. The first frame is a `start`
11234 * event carrying the persisted assistant message id (so clients
11235 * can poll the row later). Subsequent frames are `delta` events,
11236 * each tagged with the `lq_ai_message_id`, the
11237 * `routed_inference_tier`, and `applied_skills`. The final frame
11238 * is either a `complete` event (success) or an `Error` envelope
11239 * (the stream ended in failure; the assistant row is persisted
11240 * with `error_code` populated for audit). Termination is
11241 * signalled by the OpenAI-style `data: [DONE]` line.
11242 */
11243 MessageStreamEvent: components["schemas"]["MessageStart"] | components["schemas"]["MessageDelta"] | components["schemas"]["MessageComplete"] | components["schemas"]["Error"];
11244 /**
11245 * @description Opening frame on the SSE stream. Carries the assistant message
11246 * id the backend generated *before* dispatch; the persisted row
11247 * will eventually carry this same id, so the client can fetch the
11248 * row later via `GET /chats/{id}/messages`.
11249 */
11250 MessageStart: {
11251 /** @enum {string} */
11252 type: "start";
11253 /** Format: uuid */
11254 lq_ai_message_id: string;
11255 /** Format: uuid */
11256 chat_id: string;
11257 };
11258 MessageDelta: {
11259 /** @enum {string} */
11260 type: "delta";
11261 delta: string;
11262 /**
11263 * Format: uuid
11264 * @description C3: the persisted assistant message id (stable across all frames).
11265 */
11266 lq_ai_message_id: string;
11267 /**
11268 * @description B4: routed tier surfaced on every chunk.
11269 * @enum {integer|null}
11270 */
11271 routed_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11272 /** @description C2: skills assembled into the prompt. */
11273 applied_skills?: string[];
11274 };
11275 MessageComplete: {
11276 /** @enum {string} */
11277 type: "complete";
11278 /** Format: uuid */
11279 lq_ai_message_id: string;
11280 message: components["schemas"]["Message"];
11281 citations?: components["schemas"]["Citation"][];
11282 /**
11283 * @description C2: skills that were successfully assembled into the prompt
11284 * for this request. Empty when no skills were attached.
11285 */
11286 applied_skills?: string[];
11287 /**
11288 * @description Donna: caller-owned file ids forwarded to the gateway as
11289 * `lq_ai_file_ids` for this turn — the echo of
11290 * `MessageCreate.file_ids` (mirrors `applied_skills`).
11291 * Turn-scoped; not persisted. Empty when none attached.
11292 */
11293 applied_file_ids?: string[];
11294 /** @enum {integer|null} */
11295 routed_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11296 routed_provider?: string | null;
11297 };
11298 Citation: {
11299 /** Format: uuid */
11300 id: string;
11301 /** Format: uuid */
11302 source_file_id: string;
11303 source_offset_start?: number;
11304 source_offset_end?: number;
11305 source_page?: number | null;
11306 /** @description Verbatim text from source — verified to appear in source */
11307 source_text: string;
11308 /** @description Citation engine verified the quote */
11309 verified?: boolean;
11310 /**
11311 * @description True when the paraphrase judge (M2-C1) returned ``partial`` — the source supports the claim but only partially. Drives the M2-C2 UI's "verified with caveats" rendering (verified-paraphrase state).
11312 * @default false
11313 */
11314 partial: boolean;
11315 };
11316 SkillSummary: {
11317 name: string;
11318 /** @description Skill version. Free-form to accommodate skills authored before the formal authoring guide; the loader defaults to ``"unversioned"`` when the source frontmatter omits this field. */
11319 version: string;
11320 /** @enum {string} */
11321 scope: "builtin" | "user" | "team";
11322 title: string;
11323 description?: string;
11324 /** @description Attribution string from the skill's ``lq_ai.author`` frontmatter (DE-316). Surfaced verbatim; absent when the frontmatter omits it. Read by the gateway's ``skill.execute`` OTel span as ``skill.author``. */
11325 author?: string;
11326 tags?: string[];
11327 /** @description Free-form jurisdiction tag (e.g., ``us``, ``regime-aware``, ``agnostic``). Surfaced verbatim from the skill's frontmatter. */
11328 jurisdiction?: string;
11329 /** @description Inference-tier floor declared by the skill, if any. The gateway's tier-floor enforcement (Task D1) consults this; C1 only surfaces the value. */
11330 minimum_inference_tier?: number;
11331 /** @description Skill's documented output format (e.g., ``report``, ``markdown``, ``structured_checklist``, ``redline``). Free-form per the corpus. */
11332 output_format?: string;
11333 };
11334 /** @description One column in an ``output_format: table`` skill (M3-C1). The Tabular Review workflow (M3-C2) runs each ``(document, column)`` cell as a Citation-Engine-grounded extraction. */
11335 ColumnSpec: {
11336 /** @description Grid column header. */
11337 name: string;
11338 /** @description Per-row extraction prompt instantiated against each document. */
11339 query: string;
11340 /** @description Per-column override of the skill-level ``ensemble_verification`` field. ``true`` routes this column's cells through Stage 4 of the Citation Engine cascade. */
11341 ensemble_verification?: boolean | null;
11342 /** @description Per-column override of the skill-level tier floor. High-stakes columns can demand Tier 4+ while routine columns route Tier 1. */
11343 minimum_inference_tier?: number | null;
11344 };
11345 Skill: components["schemas"]["SkillSummary"] & {
11346 /**
11347 * Format: uuid
11348 * @description Wave D.2 — underlying ``user_skills.id`` row UUID when the resolved scope is ``user`` or ``team``. ``null`` for built-in (filesystem-canonical) skills, which have no DB row. The skill detail page's Versions tab needs this id to call the audit-history endpoint; surfacing it on the detail GET avoids a second round-trip to resolve slug → id.
11349 */
11350 id?: string | null;
11351 /** @description Frontmatter YAML */
11352 content_yaml: string;
11353 /** @description Body markdown */
11354 content_md: string;
11355 reference_files?: {
11356 path: string;
11357 content: string;
11358 }[];
11359 example_files?: {
11360 path: string;
11361 content: string;
11362 }[];
11363 /** @description M3-C1 — column definitions for ``output_format: table`` skills. ``null`` for non-table skills. The validator rejects ``output_format: table`` skills that lack a non-empty ``columns`` list at load time. */
11364 columns?: components["schemas"]["ColumnSpec"][] | null;
11365 /** @description Connector identifiers the skill declares it uses (C5). */
11366 tool_usage?: string[] | null;
11367 /** @description Declared connectors not configured in this deployment; null when undeterminable. Informational, never gating. */
11368 unavailable_tool_usage?: string[] | null;
11369 };
11370 SkillInputDef: {
11371 name: string;
11372 /** @description Free-form per corpus reality (text, enum, boolean, integer, structured, file, ...). */
11373 type?: string | null;
11374 /** @default false */
11375 required: boolean;
11376 description?: string | null;
11377 enum?: string[] | null;
11378 default?: unknown;
11379 };
11380 SkillInputs: {
11381 name: string;
11382 required: components["schemas"]["SkillInputDef"][];
11383 optional: components["schemas"]["SkillInputDef"][];
11384 };
11385 EnhancePromptAttachedSkill: {
11386 name: string;
11387 description?: string | null;
11388 };
11389 EnhancePromptAttachedFile: {
11390 /** Format: uuid */
11391 file_id?: string | null;
11392 filename: string;
11393 mime_type?: string | null;
11394 description?: string | null;
11395 };
11396 EnhancePromptRequest: {
11397 raw_input: string;
11398 /** Format: uuid */
11399 chat_id?: string | null;
11400 attached_skills?: components["schemas"]["EnhancePromptAttachedSkill"][];
11401 attached_files?: components["schemas"]["EnhancePromptAttachedFile"][];
11402 jurisdiction?: string | null;
11403 /** @description Optional model alias override. Defaults to ``fast``. */
11404 model?: string | null;
11405 };
11406 EnhancePromptResponse: {
11407 /** Format: uuid */
11408 interaction_id: string;
11409 expansion_applied: boolean;
11410 /**
11411 * @description The expansion when ``expansion_applied=true``, or the original
11412 * ``raw_input`` (echoed back for client convenience) when
11413 * ``expansion_applied=false``.
11414 */
11415 expanded_prompt: string;
11416 reasoning: string[];
11417 skip_reason?: string | null;
11418 /** @description Human-readable render of the expansion + reasoning the application can show in the review screen. */
11419 preview_to_user?: string;
11420 routed_inference_tier?: number | null;
11421 routed_provider?: string | null;
11422 routed_model?: string | null;
11423 };
11424 /** @description All fields optional; only supplied keys move. */
11425 EnhancePromptOutcomeUpdate: {
11426 used?: boolean | null;
11427 edited_before_use?: boolean | null;
11428 };
11429 CurrentTierResponse: {
11430 provider: string;
11431 model: string;
11432 routed_inference_tier?: number | null;
11433 routed_provider_type?: string | null;
11434 explanation?: string;
11435 };
11436 TierConfigResponse: {
11437 allowed_tiers_global: number[];
11438 default_minimum_tier: number;
11439 privileged_minimum_tier: number;
11440 warn_on_tiers: number[];
11441 };
11442 UsageRow: {
11443 group_key: string;
11444 request_count: number;
11445 tokens_in_sum: number;
11446 tokens_out_sum: number;
11447 cost_estimate_sum: number;
11448 };
11449 UsageResponse: {
11450 rows: components["schemas"]["UsageRow"][];
11451 /** @enum {string} */
11452 group_by: "user" | "provider" | "model" | "tier" | "day";
11453 total_request_count: number;
11454 total_tokens_in: number;
11455 total_tokens_out: number;
11456 total_cost_estimate: number;
11457 };
11458 ChatSearchHit: {
11459 /** Format: uuid */
11460 chat_id: string;
11461 title: string;
11462 snippet: string;
11463 /** @enum {string} */
11464 match_source: "title" | "message";
11465 rank: number;
11466 /** Format: date-time */
11467 created_at: string;
11468 /** Format: date-time */
11469 updated_at: string;
11470 };
11471 ChatSearchResponse: {
11472 items: components["schemas"]["ChatSearchHit"][];
11473 query: string;
11474 };
11475 File: {
11476 /** Format: uuid */
11477 id: string;
11478 /** Format: uuid */
11479 owner_id: string;
11480 /** Format: uuid */
11481 project_id?: string | null;
11482 filename: string;
11483 mime_type: string;
11484 size_bytes: number;
11485 hash_sha256?: string;
11486 /**
11487 * @description Lifecycle: `pending` (just uploaded; C4 sets this on insert)
11488 * → `processing` (C5 worker has picked it up) → `ready`
11489 * (parsed, chunks persisted) OR `failed` (with `ingestion_error`
11490 * set; e.g., `unsupported_type` for unsupported MIMEs (anything
11491 * that is neither PDF nor text/Markdown), `decode_error` for a
11492 * non-UTF-8 text upload, or `parse_failed` for corrupt PDFs).
11493 * @enum {string}
11494 */
11495 ingestion_status?: "pending" | "processing" | "ready" | "failed";
11496 /**
11497 * @description Set when `ingestion_status='failed'`. Values include
11498 * `unsupported_type`, `unsupported_content`, `parse_failed`,
11499 * and `decode_error` (a `text/plain` or `text/markdown` upload
11500 * whose bytes are not valid UTF-8).
11501 */
11502 ingestion_error?: string | null;
11503 /**
11504 * @description Populated by the C5 document pipeline once
11505 * `ingestion_status='ready'`; `null` while pending /
11506 * processing / failed.
11507 */
11508 page_count?: number | null;
11509 /**
11510 * @description Populated by the C5 document pipeline once
11511 * `ingestion_status='ready'`; counts characters of the
11512 * canonical extracted text (PyMuPDF for PDF; the verbatim
11513 * decoded bytes for text/Markdown), not the original byte
11514 * stream.
11515 */
11516 character_count?: number | null;
11517 /**
11518 * Format: uuid
11519 * @description UUID of the parsed-content `documents` row (M3-A6 Phase 6).
11520 * Distinct from `id` (the File UUID). `null` until the C5
11521 * parse pipeline produces the row; the Easy Playbook wizard
11522 * polls `GET /files/{id}` until this flips non-null, then
11523 * passes the value to `POST /playbooks/easy` in `document_ids`.
11524 */
11525 document_id?: string | null;
11526 /** Format: date-time */
11527 created_at: string;
11528 };
11529 KnowledgeBase: {
11530 /** Format: uuid */
11531 id: string;
11532 name: string;
11533 description?: string | null;
11534 /** Format: uuid */
11535 owner_id: string;
11536 /** Format: uuid */
11537 project_id?: string | null;
11538 /**
11539 * @description Per-KB default for the hybrid score combine. 0 = vector-only;
11540 * 1 = FTS-only; 0.5 = balanced (per ADR 0008).
11541 */
11542 hybrid_alpha: number;
11543 file_count: number;
11544 chunk_count: number;
11545 /** Format: date-time */
11546 archived_at?: string | null;
11547 /** Format: date-time */
11548 created_at: string;
11549 /** Format: date-time */
11550 updated_at: string;
11551 };
11552 KnowledgeBaseCreate: {
11553 name: string;
11554 description?: string | null;
11555 /** Format: uuid */
11556 project_id?: string | null;
11557 /** @default 0.5 */
11558 hybrid_alpha: number;
11559 };
11560 KnowledgeBaseUpdate: {
11561 name?: string;
11562 description?: string | null;
11563 /** Format: uuid */
11564 project_id?: string | null;
11565 hybrid_alpha?: number;
11566 /** @description true to archive; false to unarchive */
11567 archived?: boolean;
11568 };
11569 /**
11570 * @description One row of `GET /api/v1/knowledge-bases/{kb_id}/files`. Mirrors
11571 * `File` (the wire shape returned by `POST /files` /
11572 * `GET /files/{id}`) and adds `attached_at` from the join row so
11573 * the Knowledge surface can sort by attach time.
11574 */
11575 KBFile: {
11576 /** Format: uuid */
11577 id: string;
11578 /** Format: uuid */
11579 owner_id: string;
11580 /** Format: uuid */
11581 project_id?: string | null;
11582 filename: string;
11583 mime_type: string;
11584 size_bytes: number;
11585 hash_sha256: string;
11586 /** @enum {string} */
11587 ingestion_status: "pending" | "processing" | "ready" | "failed";
11588 ingestion_error?: string | null;
11589 page_count?: number | null;
11590 character_count?: number | null;
11591 /**
11592 * Format: uuid
11593 * @description The parsed-content `documents` row UUID, distinct from `id`
11594 * (the File UUID). Null until the C5 parse pipeline produces
11595 * a documents row. Added in M3-A4 so playbook-execute callers
11596 * can resolve File → Document client-side without a second
11597 * fetch.
11598 */
11599 document_id?: string | null;
11600 /** Format: date-time */
11601 created_at: string;
11602 /**
11603 * Format: date-time
11604 * @description When the file was attached to this KB (from
11605 * `knowledge_base_files.attached_at`).
11606 */
11607 attached_at: string;
11608 };
11609 KBQueryRequest: {
11610 query: string;
11611 /** @default 10 */
11612 top_k: number;
11613 /**
11614 * @description Override the KB's stored alpha for this query. Omit to use
11615 * the KB default.
11616 */
11617 hybrid_alpha?: number;
11618 };
11619 KBQueryResponse: {
11620 results: components["schemas"]["SearchResult"][];
11621 /** @description The alpha actually used (per-query override or KB default). */
11622 hybrid_alpha: number;
11623 };
11624 SearchResult: {
11625 chunk: {
11626 /** Format: uuid */
11627 id: string;
11628 /** Format: uuid */
11629 document_id: string;
11630 /** Format: uuid */
11631 file_id: string;
11632 file_name: string;
11633 content: string;
11634 page_start?: number | null;
11635 page_end?: number | null;
11636 char_offset_start: number;
11637 char_offset_end: number;
11638 };
11639 /** @description Combined hybrid score: (1 - alpha) * vector + alpha * fts. Min-max normalized; in [0, 1]. */
11640 score: number;
11641 score_components: {
11642 vector: number;
11643 fts: number;
11644 };
11645 };
11646 SavedPrompt: {
11647 /** Format: uuid */
11648 id: string;
11649 /** Format: uuid */
11650 user_id: string;
11651 name: string;
11652 prompt_text: string;
11653 tags?: string[];
11654 /** Format: date-time */
11655 created_at: string;
11656 /** Format: date-time */
11657 updated_at?: string;
11658 };
11659 UserSkill: {
11660 /** Format: uuid */
11661 id: string;
11662 /**
11663 * @description 'user' is owned by ``owner_user_id``; 'team' is owned by ``owner_team_id`` (D8.1b).
11664 * @enum {string}
11665 */
11666 scope: "user" | "team";
11667 /**
11668 * Format: uuid
11669 * @description Set when scope='user'; null when scope='team'. Exactly one of owner_user_id / owner_team_id is non-null (enforced by ck_user_skills_scope_owner_consistency).
11670 */
11671 owner_user_id?: string | null;
11672 /**
11673 * Format: uuid
11674 * @description Set when scope='team' (D8.1b). null when scope='user'.
11675 */
11676 owner_team_id?: string | null;
11677 /** @description Stable identifier; matches filesystem skill folder-name conventions. */
11678 slug: string;
11679 display_name: string;
11680 description: string;
11681 /** @description User-set free-form semver (e.g. "1.0.0"). */
11682 version: string;
11683 tags?: string[];
11684 /** @description Arbitrary ``lq_ai:`` extension keys (jurisdiction, output_format, minimum_inference_tier, etc.). */
11685 frontmatter_extra?: {
11686 [key: string]: unknown;
11687 };
11688 body: string;
11689 /** @description Chat-composer trigger alias (e.g. ``/nda``). Added by migration 0023. */
11690 slash_alias?: string | null;
11691 /** @description Slug of the source skill when this row was forked. Added by migration 0023. */
11692 forked_from?: string | null;
11693 /**
11694 * Format: date-time
11695 * @description Soft-delete timestamp; null when active.
11696 */
11697 archived_at?: string | null;
11698 /** Format: date-time */
11699 created_at: string;
11700 /** Format: date-time */
11701 updated_at: string;
11702 };
11703 UserSkillCreate: {
11704 slug: string;
11705 display_name: string;
11706 description: string;
11707 body: string;
11708 /** @default 1.0.0 */
11709 version: string;
11710 tags?: string[];
11711 frontmatter_extra?: {
11712 [key: string]: unknown;
11713 };
11714 /**
11715 * @description Defaults to 'user'. 'team' (D8.1b) requires owner_team_id and gates on team-admin role.
11716 * @default user
11717 * @enum {string}
11718 */
11719 scope: "user" | "team";
11720 /**
11721 * Format: uuid
11722 * @description Required when scope='team'; must be null when scope='user'. 422 if the combination is inconsistent. 404 if the caller is not a team-admin of the named team (id-probing-safe).
11723 */
11724 owner_team_id?: string | null;
11725 /**
11726 * @description Optional chat-composer trigger alias (e.g. ``/nda``). Must be
11727 * ``/`` followed by 1–32 lowercase alphanumeric-or-dash chars.
11728 * Unique per owner within the active (non-archived) set; 422 on
11729 * collision with ``"slash_alias '...' is already used by another
11730 * of your skills."``.
11731 */
11732 slash_alias?: string | null;
11733 /**
11734 * @description Slug of the source skill when this row was created by forking a
11735 * built-in or another skill via the detail-page fork button. Set
11736 * on create; read-only afterward. Stored as plain text (no FK —
11737 * the source may be a filesystem-canonical built-in with no DB row).
11738 */
11739 forked_from?: string | null;
11740 };
11741 /** @description All fields optional; only supplied keys are updated. */
11742 UserSkillUpdate: {
11743 display_name?: string;
11744 description?: string;
11745 body?: string;
11746 version?: string;
11747 tags?: string[];
11748 frontmatter_extra?: {
11749 [key: string]: unknown;
11750 };
11751 /**
11752 * @description Update the chat-composer trigger alias. Same validation and
11753 * uniqueness rules as on create. 422 on collision.
11754 */
11755 slash_alias?: string | null;
11756 };
11757 TeamSummary: {
11758 /** Format: uuid */
11759 id: string;
11760 slug: string;
11761 name: string;
11762 description?: string | null;
11763 /** Format: uuid */
11764 created_by_user_id: string;
11765 /** Format: date-time */
11766 created_at: string;
11767 /** Format: date-time */
11768 updated_at: string;
11769 member_count?: number;
11770 /**
11771 * @description The caller's role on this team (D8.1c). Populated by the
11772 * user-facing ``GET /api/v1/teams`` and
11773 * ``GET /api/v1/teams/{id}`` endpoints. Null on operator-admin
11774 * views (``/admin/teams``) when the admin isn't a member.
11775 * @enum {string|null}
11776 */
11777 caller_role?: "admin" | "member" | null;
11778 };
11779 TeamMember: {
11780 /** Format: uuid */
11781 user_id: string;
11782 email: string;
11783 display_name?: string | null;
11784 /** @enum {string} */
11785 role: "admin" | "member";
11786 /** Format: uuid */
11787 added_by_user_id: string;
11788 /** Format: date-time */
11789 created_at: string;
11790 };
11791 Team: components["schemas"]["TeamSummary"] & {
11792 members?: components["schemas"]["TeamMember"][];
11793 };
11794 TeamCreate: {
11795 slug: string;
11796 name: string;
11797 description?: string | null;
11798 };
11799 TeamUpdate: {
11800 name?: string;
11801 description?: string | null;
11802 };
11803 AuditLogEntry: {
11804 /** Format: uuid */
11805 id: string;
11806 /** Format: date-time */
11807 timestamp: string;
11808 /** Format: uuid */
11809 user_id?: string | null;
11810 /** @description e.g. chat.create, message.send, skill.fork */
11811 action: string;
11812 /** @description e.g. chat, project, skill */
11813 resource_type: string;
11814 resource_id?: string | null;
11815 privilege_marked?: boolean;
11816 /** @description Why this entry was marked privileged */
11817 privilege_basis?: string | null;
11818 /** @enum {integer|null} */
11819 routed_inference_tier?: 1 | 2 | 3 | 4 | 5 | null;
11820 ip_address?: string | null;
11821 user_agent?: string | null;
11822 details?: {
11823 [key: string]: unknown;
11824 };
11825 };
11826 TierPolicy: {
11827 /** @description Tiers globally allowed; requests at other tiers refused */
11828 allowed_tiers_global: (1 | 2 | 3 | 4 | 5)[];
11829 /**
11830 * @description Default minimum tier for non-privileged work
11831 * @enum {integer}
11832 */
11833 default_minimum_tier: 1 | 2 | 3 | 4 | 5;
11834 /**
11835 * @description Minimum tier when privileged: true on Project
11836 * @enum {integer}
11837 */
11838 privileged_minimum_tier?: 1 | 2 | 3 | 4 | 5;
11839 /** @description Tiers that surface a warning in the chat UI */
11840 warn_on_tiers?: (1 | 2 | 3 | 4 | 5)[];
11841 };
11842 AdminAliasFallback: {
11843 provider: string;
11844 model: string;
11845 };
11846 AdminAliasEntry: {
11847 name: string;
11848 provider: string;
11849 model: string;
11850 fallback: components["schemas"]["AdminAliasFallback"][];
11851 /** @enum {integer} */
11852 primary_inference_tier?: 1 | 2 | 3 | 4 | 5;
11853 };
11854 AdminAliasCreate: {
11855 name: string;
11856 provider: string;
11857 model: string;
11858 fallback?: components["schemas"]["AdminAliasFallback"][];
11859 };
11860 AdminAliasUpdate: {
11861 provider: string;
11862 model: string;
11863 fallback?: components["schemas"]["AdminAliasFallback"][];
11864 };
11865 ProviderKeySetRequest: {
11866 /** @description Name of an already-configured provider entry. */
11867 provider: string;
11868 /**
11869 * @description Plaintext provider key. The gateway encrypts it with the
11870 * gateway master key before it touches disk; it is never echoed
11871 * back in any response.
11872 */
11873 api_key: string;
11874 };
11875 ProviderKeyRotateRequest: {
11876 /**
11877 * @description Replacement plaintext provider key. Same handling as
11878 * ProviderKeySetRequest.api_key.
11879 */
11880 api_key: string;
11881 };
11882 MCPToolView: {
11883 name: string;
11884 description?: string | null;
11885 parameters?: {
11886 [key: string]: unknown;
11887 };
11888 read_only: boolean;
11889 destructive: boolean;
11890 requires_confirmation: boolean;
11891 enabled: boolean;
11892 };
11893 MCPServerView: {
11894 name: string;
11895 type: string;
11896 /**
11897 * @description Authentication mode for this MCP server. One of ``none``,
11898 * ``bearer``, or ``oauth``. Read from the gateway config
11899 * ``auth`` field; defaults to ``none`` when absent.
11900 * @enum {string}
11901 */
11902 auth: "none" | "bearer" | "oauth";
11903 tools: components["schemas"]["MCPToolView"][];
11904 };
11905 MCPServersResponse: {
11906 servers: components["schemas"]["MCPServerView"][];
11907 };
11908 MCPRefreshResponse: {
11909 server: string;
11910 tools: components["schemas"]["MCPToolView"][];
11911 };
11912 MCPToolEnableRequest: {
11913 enabled: boolean;
11914 };
11915 MCPOAuthCallbackResponse: {
11916 connected: boolean;
11917 server: string;
11918 scopes: string[];
11919 /** Format: date-time */
11920 expires_at?: string | null;
11921 };
11922 MCPOAuthStatusResponse: {
11923 connected: boolean;
11924 scopes: string[];
11925 /** Format: date-time */
11926 expires_at?: string | null;
11927 };
11928 /**
11929 * @description PR4d Ask 1. Per-server OAuth connection status for a single user.
11930 * Token bytes are never included.
11931 */
11932 MCPOAuthServerStatus: {
11933 server: string;
11934 connected: boolean;
11935 scopes: string[];
11936 /** Format: date-time */
11937 expires_at?: string | null;
11938 };
11939 /**
11940 * @description PR4d Ask 1. Response body for GET /api/v1/mcp/oauth — list of all
11941 * connectable OAuth MCP servers with the calling user's connection state.
11942 */
11943 MCPOAuthServersResponse: {
11944 servers: components["schemas"]["MCPOAuthServerStatus"][];
11945 };
11946 /**
11947 * @description Secret-safe status for one provider. Carries at most the last 4
11948 * characters of the resolved key — never the full key or token.
11949 */
11950 ProviderKeyStatus: {
11951 provider: string;
11952 /**
11953 * @description The provider's adapter type. Null only in the rare race where a
11954 * provider is removed between the write and the status read-back on
11955 * a single-provider (POST/PATCH) response; never null on the list.
11956 */
11957 type: string | null;
11958 /**
11959 * @description True when the provider has a live, routable adapter (its key
11960 * resolved). A keyless or unresolvable provider is false.
11961 */
11962 configured: boolean;
11963 /**
11964 * @description Last 4 characters of the resolved key, or null when the key is
11965 * absent, unresolvable, or shorter than 4 characters.
11966 */
11967 last4: string | null;
11968 /**
11969 * @description Key source: `runtime` (encrypted-at-rest in gateway.yaml),
11970 * `env` (api_key_env), or null (no key configured).
11971 * @enum {string|null}
11972 */
11973 source: "env" | "runtime" | null;
11974 };
11975 ProviderKeyList: {
11976 provider_keys: components["schemas"]["ProviderKeyStatus"][];
11977 };
11978 ToolCallDecisionRequest: {
11979 /**
11980 * @description Whether to approve or deny the pending tool call.
11981 * @enum {string}
11982 */
11983 decision: "approve" | "deny";
11984 };
11985 /**
11986 * @description Canonical structured error envelope returned by every backend
11987 * endpoint that raises a typed error (`LQAIError` subclass).
11988 * Implemented by the FastAPI exception handler in
11989 * `api/app/main.py`; per ADR 0003 the wrapper key is `detail`
11990 * (matching FastAPI's native `HTTPException` response and the
11991 * existing B2 forced-password-change pattern). The inner shape
11992 * — `code` + `message` + `details` — is the load-bearing
11993 * contract and matches the shape the gateway uses on its side
11994 * under the `error` wrapper (see gateway-openapi.yaml's
11995 * `GatewayError`).
11996 *
11997 * The pre-existing 501 stub envelope (returned by un-implemented
11998 * endpoints during M1 buildout, A4 scaffold) uses the legacy
11999 * `{"error": {...}}` wrapper instead. Each stub is replaced by a
12000 * real handler as its M1 task lands; new typed errors all use
12001 * the `detail` wrapper above.
12002 */
12003 Error: {
12004 detail: {
12005 /**
12006 * @description Stable error code. Backend-only codes:
12007 * `password_change_required`, `payload_too_large`,
12008 * `conflict`, `unauthorized`, `forbidden`, `not_found`,
12009 * `validation_error`, `rate_limited`, `internal_error`.
12010 * Backend↔gateway crossing codes (propagated from gateway
12011 * responses):
12012 * `gateway_unreachable`, `gateway_timeout`,
12013 * `gateway_invalid_response`, `provider_unavailable`,
12014 * `tier_below_minimum`, `invalid_model`,
12015 * `skill_not_found`, `skill_fetch_failed`,
12016 * `skill_input_missing` (C2).
12017 * @enum {string}
12018 */
12019 code: "password_change_required" | "payload_too_large" | "conflict" | "unauthorized" | "forbidden" | "not_found" | "validation_error" | "rate_limited" | "internal_error" | "gateway_unreachable" | "gateway_timeout" | "gateway_invalid_response" | "provider_unavailable" | "tier_below_minimum" | "invalid_model" | "skill_not_found" | "skill_fetch_failed" | "skill_input_missing";
12020 message: string;
12021 details?: {
12022 [key: string]: unknown;
12023 };
12024 };
12025 };
12026 };
12027 responses: never;
12028 parameters: never;
12029 requestBodies: never;
12030 headers: never;
12031 pathItems: never;
12032}
12033export type $defs = Record<string, never>;
12034export type operations = Record<string, never>;
12035