openapi: 3.1.0 info: title: DevRunbook API version: 0.2.0 description: Reference MVP contract. Runtime routes must be tested against this specification and preserve workspace authorization, immutable snapshots and safe error behavior. servers: - url: /api/v1 tags: - name: Instance - name: Authentication - name: Administration - name: Library - name: Playbooks - name: Repositories - name: Composition - name: Generated tasks - name: Artifacts - name: Integrations - name: Operations - name: Health paths: /instance/status: get: operationId: getInstanceStatus summary: Read setup and instance state responses: '200': description: Instance status content: application/json: schema: $ref: '#/components/schemas/InstanceStatus' tags: - Instance /instance/setup: post: operationId: completeInstanceSetup summary: Complete protected first-run setup responses: '201': description: Setup completed content: application/json: schema: $ref: '#/components/schemas/InstanceStatus' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetupRequest' tags: - Instance /auth/login: post: operationId: login summary: Create a revocable local session responses: '200': description: Authenticated actor content: application/json: schema: $ref: '#/components/schemas/Actor' '401': $ref: '#/components/responses/UnauthorizedResponse' '429': $ref: '#/components/responses/RateLimitedResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' tags: - Authentication /auth/logout: post: operationId: logout summary: Revoke the current session responses: '204': description: Session revoked security: - cookieAuth: [] tags: - Authentication /auth/sessions: get: operationId: listSessions summary: List the actor sessions responses: '200': description: Session list content: application/json: schema: type: array items: $ref: '#/components/schemas/Session' security: - cookieAuth: [] tags: - Authentication /auth/sessions/{sessionId}: delete: operationId: revokeSession summary: Revoke one session responses: '204': description: Session revoked '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: sessionId required: true schema: type: string security: - cookieAuth: [] tags: - Authentication /users: get: operationId: listUsers summary: List instance users responses: '200': description: User page content: application/json: schema: $ref: '#/components/schemas/UserPage' '403': $ref: '#/components/responses/ForbiddenResponse' parameters: - in: query name: q description: Case-insensitive project display-name search required: false schema: type: string minLength: 1 maxLength: 200 - in: query name: cursor required: false schema: type: string - in: query name: status required: false schema: type: string security: - cookieAuth: [] tags: - Administration /invitations: post: operationId: createInvitation summary: Create a single-use invitation responses: '201': description: Invitation content: application/json: schema: $ref: '#/components/schemas/Invitation' '403': $ref: '#/components/responses/ForbiddenResponse' '422': $ref: '#/components/responses/ValidationResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/InvitationCreateRequest' security: - cookieAuth: [] tags: - Administration /account/personal-data: post: operationId: exportPersonalData summary: Export all data associated with the authenticated user requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - password properties: password: type: string format: password writeOnly: true responses: '200': description: Personal data JSON export content: application/json: schema: type: object additionalProperties: true '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' security: - cookieAuth: [] tags: - Authentication delete: operationId: deletePersonalData summary: Anonymize the authenticated user and revoke all sessions requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - password properties: password: type: string format: password writeOnly: true responses: '204': description: User identity anonymized and sessions revoked '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '409': description: Ownership transfer is required before deletion security: - cookieAuth: [] tags: - Authentication /playbooks: get: operationId: listPlaybooks summary: Search accessible published playbooks responses: '200': description: Playbook page content: application/json: schema: $ref: '#/components/schemas/PlaybookPage' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: query name: q required: false schema: type: string maxLength: 200 - in: query name: category required: false schema: type: array items: type: string maxLength: 80 style: form explode: true - in: query name: type required: false schema: type: array items: type: string enum: - quick - guided - run-pack style: form explode: true - in: query name: mode required: false schema: type: array items: type: string enum: - inspect - plan - guided - execute - recovery style: form explode: true - in: query name: autonomy required: false schema: type: array items: type: string enum: - observe - diagnose - plan - implement - verify - repair style: form explode: true - in: query name: riskTier required: false schema: type: array items: type: string enum: - low - moderate - high - critical style: form explode: true - in: query name: lifecycle required: false schema: type: array items: type: string enum: - draft - reviewed - validated - battle-tested - deprecated style: form explode: true - in: query name: source required: false schema: type: array items: type: string enum: - built_in - private - imported style: form explode: true - in: query name: stack required: false schema: type: array items: type: string maxLength: 80 style: form explode: true - in: query name: quality required: false schema: type: array items: type: string enum: - unreviewed - editorial-reviewed - technical-reviewed - evaluation-backed style: form explode: true - in: query name: favorite required: false schema: type: boolean enum: - true description: When true, restrict the result to saved favorites. - in: query name: sort required: false schema: type: string enum: - relevance - updated - title - quality - in: query name: cursor required: false schema: type: string maxLength: 500 - in: query name: limit required: false schema: type: integer minimum: 1 maximum: 100 default: 50 security: - cookieAuth: [] tags: - Playbooks /playbooks/{slug}: get: operationId: getPlaybook summary: Read stable playbook identity and current version responses: '200': description: Playbook detail content: application/json: schema: $ref: '#/components/schemas/PlaybookDetail' '404': $ref: '#/components/responses/NotFoundResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: slug required: true schema: type: string maxLength: 80 pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ security: - cookieAuth: [] tags: - Playbooks /playbooks/{slug}/versions/{version}: get: operationId: getPlaybookVersion summary: Read an exact immutable playbook version responses: '200': description: Playbook version content: application/json: schema: $ref: '#/components/schemas/PlaybookVersion' '404': $ref: '#/components/responses/NotFoundResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: slug required: true schema: type: string maxLength: 80 pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ - in: path name: version required: true schema: type: string pattern: ^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$ security: - cookieAuth: [] tags: - Playbooks /playbook-imports: post: operationId: importPlaybookPackage summary: Import a Playbook Package ZIP responses: '201': description: Validated private draft created content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookImportResult' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '409': $ref: '#/components/responses/ConflictResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' requestBody: required: true content: application/zip: schema: type: string format: binary security: - cookieAuth: [] tags: - Playbooks /private-playbooks: get: operationId: listPrivatePlaybooks summary: List private playbook versions in the active workspace responses: '200': description: Workspace-scoped private playbook versions content: application/json: schema: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/PrivatePlaybookSummary' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' security: - cookieAuth: [] tags: - Playbooks /private-playbooks/{versionId}: get: operationId: getPrivatePlaybookVersion summary: Read one workspace-scoped private playbook draft responses: '200': description: Complete safe authoring projection content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookDetail' '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: versionId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Playbooks put: operationId: replacePrivatePlaybookVersion summary: Validate and atomically replace a mutable private package responses: '200': description: Updated private draft content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookDetail' '409': $ref: '#/components/responses/ConflictResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '428': description: If-Match precondition required parameters: - in: path name: versionId required: true schema: type: string format: uuid - in: header name: If-Match required: true schema: type: string requestBody: required: true content: application/zip: schema: type: string format: binary application/json: schema: type: object additionalProperties: false required: - files properties: files: type: array maxItems: 201 items: type: object additionalProperties: false required: - path - role - encoding - content properties: path: type: string role: type: string encoding: type: string enum: - utf8 - base64 content: type: string security: - cookieAuth: [] tags: - Playbooks /private-playbooks/{versionId}/export: get: operationId: exportPrivatePlaybookVersion summary: Export an authorized private package as deterministic ZIP responses: '200': description: Playbook Package ZIP content: application/zip: schema: type: string format: binary '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: versionId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Playbooks /private-playbooks/{versionId}/review: post: operationId: reviewPrivatePlaybookVersion summary: Record digest-bound editorial and lint evidence responses: '200': description: Review evidence recorded content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookReviewResult' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: versionId required: true schema: type: string format: uuid - in: header name: If-Match required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookReviewRequest' security: - cookieAuth: [] tags: - Playbooks /private-playbooks/{versionId}/versions: post: operationId: createNextPrivatePlaybookVersion summary: Clone an immutable published version into a new draft version responses: '201': description: New mutable draft version created content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookVersionCreated' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: versionId required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePrivatePlaybookVersionRequest' security: - cookieAuth: [] tags: - Playbooks /playbooks/{playbookId}/versions/{version}/publish: post: operationId: publishPlaybookVersion summary: Publish an immutable private version responses: '200': description: Published version content: application/json: schema: $ref: '#/components/schemas/PrivatePlaybookSummary' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: playbookId required: true schema: type: string - in: header name: If-Match required: true schema: type: string - in: path name: version required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublishRequest' security: - cookieAuth: [] tags: - Playbooks /favorites/{playbookId}: put: operationId: favoritePlaybook summary: Add playbook favorite responses: '204': description: Favorite stored '404': $ref: '#/components/responses/NotFoundResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: playbookId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Library delete: operationId: unfavoritePlaybook summary: Remove playbook favorite responses: '204': description: Favorite removed '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: playbookId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Library /collections: get: operationId: listCollections summary: List the current user's personal collections in the workspace responses: '200': description: Collection list content: application/json: schema: type: array items: $ref: '#/components/schemas/Collection' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' security: - cookieAuth: [] tags: - Library post: operationId: createCollection summary: Create a personal collection in the workspace responses: '201': description: Collection created content: application/json: schema: $ref: '#/components/schemas/Collection' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CollectionCreateRequest' security: - cookieAuth: [] tags: - Library /collections/{collectionId}/playbooks/{playbookId}: put: operationId: addPlaybookToCollection summary: Add an accessible playbook to a personal collection responses: '204': description: Playbook is in the collection '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: collectionId required: true schema: type: string format: uuid - in: path name: playbookId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Library delete: operationId: removePlaybookFromCollection summary: Remove a playbook from a personal collection responses: '204': description: Playbook is absent from the collection '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: collectionId required: true schema: type: string format: uuid - in: path name: playbookId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Library /repositories: get: operationId: listRepositories summary: List workspace repositories responses: '200': description: Repository page content: application/json: schema: $ref: '#/components/schemas/RepositoryPage' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: query name: cursor required: false schema: type: string minLength: 1 maxLength: 500 - in: query name: limit required: false schema: type: integer minimum: 1 maximum: 100 default: 50 - in: query name: source required: false schema: enum: - manual - gitea - in: query name: archived required: false schema: type: boolean security: - cookieAuth: [] tags: - Repositories post: operationId: createRepository summary: Atomically create a manual repository and its initial profile revision responses: '201': description: Repository and initial profile revision created headers: ETag: $ref: '#/components/headers/StrongETag' content: application/json: schema: $ref: '#/components/schemas/RepositoryCreateResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' requestBody: required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/RepositoryCreateRequest' - $ref: '#/components/schemas/RepositoryProfile' application/yaml: schema: $ref: '#/components/schemas/RepositoryProfile' security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}: get: operationId: getRepository summary: Read repository workspace summary responses: '200': description: Repository content: application/json: schema: $ref: '#/components/schemas/Repository' '404': $ref: '#/components/responses/NotFoundResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Repositories delete: operationId: deleteRepository summary: Delete or detach a repository responses: '204': description: Repository deleted '409': $ref: '#/components/responses/ConflictResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}/profile: get: operationId: getRepositoryProfile summary: Read current profile revision responses: '200': description: Repository profile headers: ETag: $ref: '#/components/headers/StrongETag' content: application/json: schema: $ref: '#/components/schemas/RepositoryProfileEnvelope' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Repositories put: operationId: createRepositoryProfileRevision summary: Validate and create a new immutable profile revision responses: '200': description: Validated profile was a semantic no-op; current revision returned unchanged headers: ETag: $ref: '#/components/headers/StrongETag' content: application/json: schema: $ref: '#/components/schemas/RepositoryProfileEnvelope' '201': description: New profile revision headers: ETag: $ref: '#/components/headers/StrongETag' content: application/json: schema: $ref: '#/components/schemas/RepositoryProfileEnvelope' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' '428': $ref: '#/components/responses/PreconditionRequiredResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid - in: header name: If-Match required: true description: Strong ETag returned with the current profile revision. schema: type: string minLength: 1 pattern: '^"profile:[1-9][0-9]*:[a-f0-9]{64}"$' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RepositoryProfile' application/yaml: schema: $ref: '#/components/schemas/RepositoryProfile' security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}/profile/export: get: operationId: exportRepositoryProfile summary: Export the current governed profile as JSON or YAML responses: '200': description: Exact current profile revision in the selected governed format headers: Content-Disposition: $ref: '#/components/headers/ContentDisposition' ETag: $ref: '#/components/headers/StrongETag' content: application/json: schema: $ref: '#/components/schemas/RepositoryProfile' application/yaml: schema: $ref: '#/components/schemas/RepositoryProfile' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid - in: query name: format required: false description: Governs serialization and Content-Disposition filename extension. schema: enum: - json - yaml default: yaml security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}/snapshots: post: operationId: createRepositorySnapshot summary: Queue a bounded read-only snapshot responses: '202': description: Snapshot job content: application/json: schema: $ref: '#/components/schemas/JobReference' '409': $ref: '#/components/responses/ConflictResponse' parameters: - in: path name: repositoryId required: true schema: type: string security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}/snapshots/{snapshotId}: get: operationId: getRepositorySnapshot summary: Read one immutable snapshot responses: '200': description: Snapshot content: application/json: schema: $ref: '#/components/schemas/RepositorySnapshot' '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: repositoryId required: true schema: type: string - in: path name: snapshotId required: true schema: type: string security: - cookieAuth: [] tags: - Repositories /repositories/{repositoryId}/findings: get: operationId: listRepositoryFindings summary: List findings from latest or selected snapshot responses: '200': description: Finding list content: application/json: schema: type: array items: $ref: '#/components/schemas/RepositoryFinding' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: repositoryId required: true schema: type: string format: uuid - in: query name: snapshotId required: false schema: type: string format: uuid - in: query name: severity required: false schema: type: string security: - cookieAuth: [] tags: - Repositories /compositions/drafts: post: operationId: createCompositionDraft summary: Create a mutable composer draft responses: '201': description: Draft headers: ETag: $ref: '#/components/headers/CompositionDraftETag' content: application/json: schema: $ref: '#/components/schemas/CompositionDraft' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '429': $ref: '#/components/responses/RateLimitedResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompositionRequest' security: - cookieAuth: [] tags: - Composition /compositions/drafts/{draftId}: get: operationId: getCompositionDraft summary: Read a composer draft responses: '200': description: Draft headers: ETag: $ref: '#/components/headers/CompositionDraftETag' content: application/json: schema: $ref: '#/components/schemas/CompositionDraft' '401': $ref: '#/components/responses/UnauthorizedResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: draftId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Composition patch: operationId: updateCompositionDraft summary: Update a draft with optimistic concurrency responses: '200': description: Updated draft headers: ETag: $ref: '#/components/headers/CompositionDraftETag' content: application/json: schema: $ref: '#/components/schemas/CompositionDraft' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '409': description: Draft changed since the supplied If-Match revision; reload and review before retrying. headers: ETag: $ref: '#/components/headers/CompositionDraftETag' content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFoundResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '428': $ref: '#/components/responses/PreconditionRequiredResponse' '429': $ref: '#/components/responses/RateLimitedResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: draftId required: true schema: type: string format: uuid - in: header name: If-Match required: true schema: type: string pattern: '^"draft:[1-9][0-9]*"$' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompositionPatchRequest' security: - cookieAuth: [] tags: - Composition /compositions/preview: post: operationId: previewComposition summary: Render deterministic non-immutable preview responses: '200': description: Composition preview content: application/json: schema: $ref: '#/components/schemas/CompositionResult' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '429': $ref: '#/components/responses/RateLimitedResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompositionRequest' security: - cookieAuth: [] tags: - Composition /runs: get: operationId: listGeneratedRuns summary: List immutable generated tasks responses: '200': description: Generated task page content: application/json: schema: $ref: '#/components/schemas/GeneratedRunPage' '401': $ref: '#/components/responses/UnauthorizedResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: query name: cursor required: false schema: type: string minLength: 1 maxLength: 500 - in: query name: repositoryId required: false schema: type: string format: uuid - in: query name: playbookSlug required: false schema: type: string pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$' maxLength: 120 - in: query name: limit required: false schema: type: integer minimum: 1 maximum: 100 default: 50 security: - cookieAuth: [] tags: - Generated tasks post: operationId: createGeneratedRun summary: Create an immutable generated task responses: '200': description: Existing generated task returned for an idempotent replay headers: Idempotency-Replayed: $ref: '#/components/headers/IdempotencyReplayed' content: application/json: schema: $ref: '#/components/schemas/GeneratedRunDetail' '201': description: Generated task content: application/json: schema: $ref: '#/components/schemas/GeneratedRunDetail' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '409': $ref: '#/components/responses/ConflictResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '429': $ref: '#/components/responses/RateLimitedResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: header name: Idempotency-Key required: true schema: type: string minLength: 1 maxLength: 255 - in: header name: X-DevRunbook-Draft-Id required: false description: Links generation to an authoritative persisted composer draft. When present, the server reloads the draft and ignores client-derived composition state. schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompositionRequest' security: - cookieAuth: [] tags: - Generated tasks /runs/{runId}: get: operationId: getGeneratedRun summary: Read an immutable generated task responses: '200': description: Generated task content: application/json: schema: $ref: '#/components/schemas/GeneratedRunDetail' '401': $ref: '#/components/responses/UnauthorizedResponse' '404': $ref: '#/components/responses/NotFoundResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: runId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Generated tasks /runs/{runId}/artifacts: post: operationId: createRunArtifact summary: Generate an immutable artifact from a historical run responses: '200': description: Existing artifact returned for an idempotent replay content: application/json: schema: $ref: '#/components/schemas/Artifact' '201': description: Artifact created synchronously content: application/json: schema: $ref: '#/components/schemas/Artifact' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: runId required: true schema: type: string format: uuid - in: header name: Idempotency-Key required: true schema: type: string minLength: 1 maxLength: 255 requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ArtifactCreateRequest' security: - cookieAuth: [] tags: - Artifacts /artifacts/{artifactId}/download: get: operationId: downloadArtifact summary: Download an authorized artifact responses: '200': description: Artifact bytes headers: Content-Disposition: schema: type: string X-Content-Type-Options: schema: type: string const: nosniff X-DevRunbook-Artifact-SHA256: schema: type: string pattern: '^[a-f0-9]{64}$' content: text/plain: schema: type: string format: binary text/markdown: schema: type: string format: binary application/zip: schema: type: string format: binary '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '410': description: Artifact retention has expired content: application/json: schema: $ref: '#/components/schemas/Error' '503': $ref: '#/components/responses/ServiceUnavailableResponse' parameters: - in: path name: artifactId required: true schema: type: string format: uuid security: - cookieAuth: [] tags: - Artifacts /run-pack-imports: post: operationId: verifyRunPackImport summary: Re-import and verify a Run Pack against its immutable historical run requestBody: required: true content: application/zip: schema: type: string format: binary responses: '200': description: Run Pack integrity and historical identity verified content: application/json: schema: $ref: '#/components/schemas/VerifiedRunPackImport' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictResponse' '413': $ref: '#/components/responses/PayloadTooLargeResponse' '422': $ref: '#/components/responses/ValidationResponse' '503': $ref: '#/components/responses/ServiceUnavailableResponse' security: - cookieAuth: [] tags: - Artifacts /integrations/gitea: get: operationId: listGiteaIntegrations summary: List safe Gitea connection metadata for the active workspace responses: '200': description: Integration list content: application/json: schema: type: array maxItems: 100 items: $ref: '#/components/schemas/Integration' security: - cookieAuth: [] tags: - Integrations post: operationId: createGiteaIntegration summary: Create encrypted read-only Gitea connection responses: '201': description: Integration content: application/json: schema: $ref: '#/components/schemas/Integration' '422': $ref: '#/components/responses/ValidationResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GiteaIntegrationCreateRequest' security: - cookieAuth: [] tags: - Integrations /integrations/gitea/{integrationId}: get: operationId: getGiteaIntegration summary: Read safe integration metadata responses: '200': description: Integration content: application/json: schema: $ref: '#/components/schemas/Integration' '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: integrationId required: true schema: type: string security: - cookieAuth: [] tags: - Integrations delete: operationId: deleteGiteaIntegration summary: Delete integration and encrypted credential responses: '204': description: Integration deleted parameters: - in: path name: integrationId required: true schema: type: string security: - cookieAuth: [] tags: - Integrations /integrations/gitea/{integrationId}/test: post: operationId: testGiteaIntegration summary: Test connection and capability snapshot responses: '200': description: Health and capabilities content: application/json: schema: $ref: '#/components/schemas/IntegrationTestResult' '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: integrationId required: true schema: type: string security: - cookieAuth: [] tags: - Integrations /integrations/gitea/{integrationId}/repositories: get: operationId: discoverGiteaRepositories summary: List accessible repositories with pagination responses: '200': description: External repository page content: application/json: schema: $ref: '#/components/schemas/ExternalRepositoryPage' parameters: - in: path name: integrationId required: true schema: type: string - in: query name: cursor required: false schema: type: string security: - cookieAuth: [] tags: - Integrations /integrations/gitea/{integrationId}/repositories/import: post: operationId: importGiteaRepository summary: Import one discovered repository and queue its first read-only snapshot responses: '202': description: Imported repository and snapshot job content: application/json: schema: $ref: '#/components/schemas/GiteaRepositoryImportResult' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictResponse' '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: integrationId required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GiteaRepositoryImportRequest' security: - cookieAuth: [] tags: - Integrations /integrations/gitea/{integrationId}/rotate-secret: post: operationId: rotateGiteaSecret summary: Replace encrypted token without returning it responses: '204': description: Secret rotated '422': $ref: '#/components/responses/ValidationResponse' parameters: - in: path name: integrationId required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SecretRotationRequest' security: - cookieAuth: [] tags: - Integrations /jobs: get: operationId: listJobs summary: List authorized safe job status responses: '200': description: Job page content: application/json: schema: $ref: '#/components/schemas/JobPage' parameters: - in: query name: cursor required: false schema: type: string - in: query name: limit required: false schema: type: integer minimum: 1 maximum: 100 - in: query name: state required: false schema: type: string enum: [queued, running, succeeded, failed, cancelled] security: - cookieAuth: [] tags: - Operations /jobs/{jobId}: get: operationId: getJob summary: Read safe job status responses: '200': description: Job content: application/json: schema: $ref: '#/components/schemas/Job' '404': $ref: '#/components/responses/NotFoundResponse' parameters: - in: path name: jobId required: true schema: type: string security: - cookieAuth: [] tags: - Operations /jobs/{jobId}/retry: post: operationId: retryJob summary: Retry a retryable failed job responses: '202': description: Retried job content: application/json: schema: $ref: '#/components/schemas/JobReference' '409': $ref: '#/components/responses/ConflictResponse' parameters: - in: path name: jobId required: true schema: type: string security: - cookieAuth: [] tags: - Operations /audit-events: get: operationId: listAuditEvents summary: List authorized audit events responses: '200': description: Audit page content: application/json: schema: $ref: '#/components/schemas/AuditEventPage' '403': $ref: '#/components/responses/ForbiddenResponse' parameters: - in: query name: cursor required: false schema: type: string - in: query name: action required: false schema: type: string - in: query name: workspaceId required: false schema: type: string security: - cookieAuth: [] tags: - Administration /settings/instance: get: operationId: getInstanceSettings summary: Read safe non-secret instance settings responses: '200': description: Instance config content: application/json: schema: $ref: '#/components/schemas/InstanceConfig' security: - cookieAuth: [] tags: - Administration put: operationId: updateInstanceSettings summary: Update validated non-secret instance settings responses: '200': description: Updated config content: application/json: schema: $ref: '#/components/schemas/InstanceConfig' '403': $ref: '#/components/responses/ForbiddenResponse' '422': $ref: '#/components/responses/ValidationResponse' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/InstanceConfig' security: - cookieAuth: [] tags: - Administration /health/live: get: operationId: liveness summary: Process liveness responses: '200': description: Process alive content: application/json: schema: $ref: '#/components/schemas/HealthStatus' tags: - Health /health/ready: get: operationId: readiness summary: Dependency and lifecycle readiness responses: '200': description: Ready content: application/json: schema: $ref: '#/components/schemas/HealthStatus' '503': description: Not ready content: application/json: schema: $ref: '#/components/schemas/HealthStatus' tags: - Health components: securitySchemes: cookieAuth: type: apiKey in: cookie name: devrunbook_session headers: StrongETag: description: Strong validator for the exact immutable profile revision representation. required: true schema: type: string pattern: '^"profile:[1-9][0-9]*:[a-f0-9]{64}"$' example: '"profile:1:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"' ContentDisposition: description: Attachment filename with a safe JSON or YAML extension. required: true schema: type: string pattern: '^attachment; filename="[a-zA-Z0-9._-]+\\.(json|ya?ml)"$' CompositionDraftETag: description: Strong validator for the exact mutable composition-draft revision. required: true schema: type: string pattern: '^"draft:[1-9][0-9]*"$' example: '"draft:3"' IdempotencyReplayed: description: Indicates that the immutable representation was returned from an earlier successful request with the same key. required: true schema: type: string const: 'true' RetryAfter: description: Whole seconds before the client should retry the rate-limited operation. required: true schema: type: integer minimum: 1 schemas: Error: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message - requestId properties: code: type: string message: type: string requestId: type: string details: type: array items: type: object additionalProperties: true InstanceStatus: type: object required: - state - setupRequired - schemaVersion properties: state: enum: - uninitialized - initializing - ready - maintenance - migration_required - recovery_required setupRequired: type: boolean schemaVersion: type: string applicationVersion: type: string warnings: type: array items: type: string SetupRequest: type: object additionalProperties: false required: - bootstrapToken - instanceName - publicBaseUrl - owner properties: bootstrapToken: type: string writeOnly: true instanceName: type: string publicBaseUrl: type: string format: uri owner: $ref: '#/components/schemas/OwnerCreateRequest' configuration: $ref: '#/components/schemas/InstanceConfig' OwnerCreateRequest: type: object additionalProperties: false required: - email - displayName - password properties: email: type: string format: email displayName: type: string password: type: string format: password writeOnly: true minLength: 12 LoginRequest: type: object additionalProperties: false required: - email - password properties: email: type: string format: email password: type: string format: password writeOnly: true Actor: type: object required: - id - email - displayName - instanceRole - workspace properties: id: type: string format: uuid email: type: string format: email displayName: type: string instanceRole: enum: - instance_owner - instance_admin - user workspace: $ref: '#/components/schemas/WorkspaceMembership' WorkspaceMembership: type: object required: - workspaceId - workspaceName - role properties: workspaceId: type: string format: uuid workspaceName: type: string role: enum: - owner - editor - viewer Session: type: object required: - id - createdAt - lastSeenAt - idleExpiresAt - absoluteExpiresAt - current properties: id: type: string createdAt: type: string format: date-time lastSeenAt: type: string format: date-time idleExpiresAt: type: string format: date-time absoluteExpiresAt: type: string format: date-time current: type: boolean userAgentSummary: type: string User: type: object required: - id - email - displayName - instanceRole - status properties: id: type: string format: uuid email: type: string format: email displayName: type: string instanceRole: enum: - instance_owner - instance_admin - user status: enum: - active - disabled - pending_deletion createdAt: type: string format: date-time UserPage: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/User' nextCursor: type: - string - 'null' InvitationCreateRequest: type: object additionalProperties: false required: - email - instanceRole properties: email: type: string format: email instanceRole: enum: - instance_admin - user workspaceId: type: - string - 'null' format: uuid workspaceRole: enum: - owner - editor - viewer Invitation: type: object required: - id - email - expiresAt - inviteUrl properties: id: type: string format: uuid email: type: string format: email expiresAt: type: string format: date-time inviteUrl: type: string format: uri writeOnly: true PlaybookSummary: type: object required: - id - slug - title - summary - category - source - currentVersion - lifecycle - riskTier - type - defaultMode - defaultAutonomy - supportedModes - autonomyMin - autonomyMax - stacks - qualityStatus - publishedAt - favorite - tags - matchReasons - digest properties: id: type: string slug: type: string title: type: string summary: type: string category: type: string source: enum: - built_in - private - imported currentVersion: type: string lifecycle: type: string riskTier: type: string type: type: string defaultMode: type: string defaultAutonomy: type: string supportedModes: type: array items: type: string autonomyMin: type: string autonomyMax: type: string stacks: type: array items: type: string qualityStatus: type: string publishedAt: type: string format: date-time favorite: type: boolean tags: type: array items: type: string matchReasons: type: array items: type: string digest: type: string pattern: ^[a-f0-9]{64}$ PlaybookPage: type: object required: - items - nextCursor - facets - search properties: items: type: array items: $ref: '#/components/schemas/PlaybookSummary' nextCursor: type: - string - 'null' facets: type: object additionalProperties: true search: type: object additionalProperties: false required: - status - total properties: status: enum: - ready - degraded total: type: integer minimum: 0 PlaybookDetail: allOf: - $ref: '#/components/schemas/PlaybookSummary' - type: object properties: current: $ref: '#/components/schemas/PlaybookVersion' versions: type: array items: type: object properties: version: type: string lifecycle: type: string publishedAt: type: - string - 'null' format: date-time digest: type: string PlaybookVersion: type: object required: - id - playbookId - version - digest - manifest - template - quality properties: id: type: string playbookId: type: string version: type: string digest: type: string pattern: ^[a-f0-9]{64}$ manifest: type: object additionalProperties: true template: type: string quality: type: object additionalProperties: true publishedAt: type: - string - 'null' format: date-time PublishRequest: type: object additionalProperties: false required: - lifecycle properties: lifecycle: type: string enum: - reviewed - validated - deprecated CreatePrivatePlaybookVersionRequest: type: object additionalProperties: false required: - semanticVersion properties: semanticVersion: type: string pattern: '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$' PrivatePlaybookVersionCreated: type: object additionalProperties: false required: - versionId - semanticVersion - slug properties: versionId: type: string format: uuid semanticVersion: type: string slug: type: string PrivatePlaybookReviewRequest: type: object additionalProperties: false required: - limitationsDocumented - unresolvedSafetyRegression - note properties: limitationsDocumented: type: boolean unresolvedSafetyRegression: type: boolean note: type: string minLength: 1 maxLength: 4000 PrivatePlaybookReviewResult: type: object additionalProperties: false required: - digest - lint - recorded properties: digest: type: string pattern: ^[a-f0-9]{64}$ recorded: type: boolean const: true lint: type: object additionalProperties: true PrivatePlaybookSummary: type: object additionalProperties: false required: - playbookId - versionId - slug - semanticVersion - title - lifecycle - draftRevision - draftDigest - publishedAt - updatedAt properties: playbookId: type: string format: uuid versionId: type: string format: uuid slug: type: string semanticVersion: type: string title: type: string lifecycle: type: string enum: - draft - reviewed - validated - battle-tested - deprecated draftRevision: type: integer minimum: 1 draftDigest: type: string pattern: ^[a-f0-9]{64}$ publishedAt: type: - string - 'null' format: date-time updatedAt: type: string format: date-time PrivatePlaybookFile: type: object additionalProperties: false required: - path - role - mediaType - sizeBytes - sha256 - digest - exportByDefault - encoding - content properties: path: type: string role: type: string mediaType: type: string sizeBytes: type: integer minimum: 0 sha256: type: string pattern: ^[a-f0-9]{64}$ digest: type: boolean exportByDefault: type: boolean encoding: type: string enum: - utf8 - base64 content: type: string PrivatePlaybookDetail: allOf: - $ref: '#/components/schemas/PrivatePlaybookSummary' - type: object required: - logicalId - summary - category - riskTier - packageApiVersion - templateText - files properties: logicalId: type: string summary: type: string category: type: string riskTier: type: string enum: - low - moderate - high - critical packageApiVersion: type: string templateText: type: string files: type: array items: $ref: '#/components/schemas/PrivatePlaybookFile' PrivatePlaybookImportResult: allOf: - $ref: '#/components/schemas/PrivatePlaybookSummary' - type: object required: - archiveSha256 properties: archiveSha256: type: string pattern: ^[a-f0-9]{64}$ Collection: type: object additionalProperties: false required: - id - name - description - itemCount - playbookIds - createdAt - updatedAt properties: id: type: string format: uuid name: type: string minLength: 1 maxLength: 80 description: type: string maxLength: 500 itemCount: type: integer minimum: 0 playbookIds: type: array items: type: string format: uuid uniqueItems: true createdAt: type: string format: date-time updatedAt: type: string format: date-time CollectionCreateRequest: type: object additionalProperties: false required: - name properties: name: type: string minLength: 1 maxLength: 80 description: type: string maxLength: 500 Repository: type: object additionalProperties: false required: - id - displayName - sourceType - archived - currentProfileRevision - createdAt - updatedAt properties: id: type: string format: uuid displayName: type: string minLength: 1 maxLength: 120 sourceType: enum: - manual - gitea defaultBranch: type: - string - 'null' archived: type: boolean integrationId: type: - string - 'null' format: uuid currentProfileRevision: type: - integer - 'null' minimum: 1 lastSnapshotAt: type: - string - 'null' format: date-time createdAt: type: string format: date-time updatedAt: type: string format: date-time RepositoryPage: type: object additionalProperties: false required: - items - nextCursor properties: items: type: array items: $ref: '#/components/schemas/Repository' nextCursor: type: - string - 'null' RepositoryCreateRequest: type: object description: Manual creation wrapper. Raw JSON/YAML RepositoryProfile bodies are imported atomically instead. additionalProperties: false required: - displayName - initialProfile properties: displayName: type: string minLength: 1 maxLength: 120 initialProfile: $ref: '#/components/schemas/RepositoryProfile' RepositoryCreateResponse: type: object additionalProperties: false required: - repository - currentProfile properties: repository: $ref: '#/components/schemas/Repository' currentProfile: $ref: '#/components/schemas/RepositoryProfileEnvelope' RepositoryProfileEnvelope: type: object additionalProperties: false required: - repositoryId - revision - contentDigest - createdAt - profile properties: repositoryId: type: string format: uuid revision: type: integer minimum: 1 contentDigest: $ref: '#/components/schemas/RepositoryProfileSha256' createdAt: type: string format: date-time profile: $ref: '#/components/schemas/RepositoryProfile' RepositoryProfile: type: object description: Strict schema-validated devrunbook.io/v1alpha1 RepositoryProfile document. additionalProperties: false required: - apiVersion - kind - metadata - spec properties: apiVersion: const: devrunbook.io/v1alpha1 kind: const: RepositoryProfile metadata: type: object additionalProperties: false required: - name - revision - source properties: name: type: string minLength: 1 maxLength: 120 revision: type: integer minimum: 1 source: enum: - manual - gitea - imported - mixed capturedAt: type: string format: date-time sourceReference: type: string maxLength: 300 contentDigest: $ref: '#/components/schemas/RepositoryProfileSha256' spec: type: object additionalProperties: false required: - repositoryType - stack - commands - paths - policies properties: repositoryType: enum: - single-app - monorepo - library - infrastructure - mixed - unknown defaultBranch: type: string maxLength: 200 stack: $ref: '#/components/schemas/RepositoryProfileStack' commands: type: array maxItems: 100 items: $ref: '#/components/schemas/RepositoryProfileCommand' paths: $ref: '#/components/schemas/RepositoryProfilePaths' policies: $ref: '#/components/schemas/RepositoryProfilePolicies' sourceFacts: type: array maxItems: 500 items: $ref: '#/components/schemas/RepositoryProfileSourceFact' manualOverrides: type: array maxItems: 200 items: $ref: '#/components/schemas/RepositoryProfileManualOverride' notes: type: string maxLength: 5000 RepositoryProfileSha256: type: string pattern: '^[a-f0-9]{64}$' RepositoryProfileCommandRole: enum: - install - format - format-check - lint - typecheck - unit-test - integration-test - end-to-end-test - build - dev-start - smoke-test - migration-status - migration-apply - security-scan - dependency-audit RepositoryProfileStringSet: type: array uniqueItems: true maxItems: 100 items: type: string minLength: 1 maxLength: 120 RepositoryProfilePathSet: type: array uniqueItems: true maxItems: 200 items: type: string minLength: 1 maxLength: 500 RepositoryProfileEvidenceSet: type: array minItems: 1 maxItems: 100 uniqueItems: true items: type: string minLength: 1 maxLength: 120 RepositoryProfileStack: type: object additionalProperties: false required: - languages - frameworks - packageManagers - databases - deploymentTypes - testFrameworks properties: languages: $ref: '#/components/schemas/RepositoryProfileStringSet' frameworks: $ref: '#/components/schemas/RepositoryProfileStringSet' packageManagers: $ref: '#/components/schemas/RepositoryProfileStringSet' databases: $ref: '#/components/schemas/RepositoryProfileStringSet' deploymentTypes: $ref: '#/components/schemas/RepositoryProfileStringSet' testFrameworks: $ref: '#/components/schemas/RepositoryProfileStringSet' services: $ref: '#/components/schemas/RepositoryProfileStringSet' runtimes: $ref: '#/components/schemas/RepositoryProfileStringSet' queues: $ref: '#/components/schemas/RepositoryProfileStringSet' ciSystems: $ref: '#/components/schemas/RepositoryProfileStringSet' RepositoryProfileCommand: type: object additionalProperties: false required: - id - role - command - workingDirectory - platform - shell - source - confirmed - safeForAgentSuggestion properties: id: type: string pattern: '^[a-z][a-z0-9-]*$' maxLength: 80 role: $ref: '#/components/schemas/RepositoryProfileCommandRole' command: type: string minLength: 1 maxLength: 1000 workingDirectory: type: string minLength: 1 maxLength: 500 platform: enum: - any - linux - windows - macos - container shell: enum: - auto - sh - bash - pwsh - cmd source: enum: - manual - manifest - documentation - gitea - inferred confirmed: type: boolean safeForAgentSuggestion: type: boolean timeoutSeconds: type: integer minimum: 1 maximum: 86400 notes: type: string maxLength: 500 confidence: enum: - low - medium - high evidence: $ref: '#/components/schemas/RepositoryProfileStringSet' observedCommand: type: string minLength: 1 maxLength: 1000 confirmedAt: type: string format: date-time RepositoryProfilePaths: type: object additionalProperties: false required: - applicationRoots - testRoots - documentationRoots - generated - protected - excluded properties: applicationRoots: $ref: '#/components/schemas/RepositoryProfilePathSet' testRoots: $ref: '#/components/schemas/RepositoryProfilePathSet' documentationRoots: $ref: '#/components/schemas/RepositoryProfilePathSet' generated: $ref: '#/components/schemas/RepositoryProfilePathSet' protected: $ref: '#/components/schemas/RepositoryProfilePathSet' excluded: $ref: '#/components/schemas/RepositoryProfilePathSet' packageRoots: $ref: '#/components/schemas/RepositoryProfilePathSet' serviceRoots: $ref: '#/components/schemas/RepositoryProfilePathSet' dataRuntime: $ref: '#/components/schemas/RepositoryProfilePathSet' ignored: $ref: '#/components/schemas/RepositoryProfilePathSet' RepositoryProfilePolicies: type: object additionalProperties: false required: - preserveBackwardCompatibility - newDependencies - gitWrite - migrations - documentationRequired - networkAccess - productionDataAccess properties: preserveBackwardCompatibility: type: boolean newDependencies: enum: - allowed - justify - approval-required - forbidden gitWrite: enum: - none - local-commit - push-with-approval migrations: enum: - forbidden - plan-only - reversible-only - allowed-with-backup documentationRequired: type: boolean networkAccess: enum: - forbidden - read-only-approved-hosts - allowed-with-approval productionDataAccess: enum: - forbidden - read-only-redacted - approval-required requiredValidationRoles: type: array uniqueItems: true maxItems: 30 items: $ref: '#/components/schemas/RepositoryProfileCommandRole' branchConventions: $ref: '#/components/schemas/RepositoryProfileStringSet' environmentConstraints: $ref: '#/components/schemas/RepositoryProfileStringSet' RepositoryProfileSourceFact: type: object additionalProperties: false required: - path - value - source - evidence properties: path: type: string pattern: '^(?:/(?:[^~/]|~0|~1)*)+$' maxLength: 500 value: {} source: enum: - manual - manifest - documentation - gitea - inferred - prior-profile evidence: $ref: '#/components/schemas/RepositoryProfileEvidenceSet' confidence: enum: - low - medium - high observedAt: type: string format: date-time RepositoryProfileManualOverride: type: object additionalProperties: false required: - path - value - observedValue - evidence - confirmedAt properties: path: type: string pattern: '^(?:/(?:[^~/]|~0|~1)*)+$' maxLength: 500 value: {} observedValue: {} evidence: $ref: '#/components/schemas/RepositoryProfileEvidenceSet' confirmedAt: type: string format: date-time note: type: string maxLength: 500 RepositorySnapshot: type: object required: - id - repositoryId - state - createdAt properties: id: type: string format: uuid repositoryId: type: string format: uuid state: enum: - collecting - complete - failed - cancelled capturedAt: type: - string - 'null' format: date-time evidenceDigest: type: - string - 'null' capabilities: type: object additionalProperties: true evidenceSummary: type: object additionalProperties: true createdAt: type: string format: date-time RepositoryFinding: type: object required: - id - severity - title - rationale - evidencePointer - status properties: id: type: string format: uuid severity: enum: - info - low - medium - high - critical title: type: string rationale: type: string evidencePointer: type: string recommendedPlaybookSlug: type: - string - 'null' status: enum: - open - dismissed - resolved CompositionRequest: type: object additionalProperties: false required: - playbook - workMode - autonomyLevel - inputs properties: playbook: type: object additionalProperties: false required: - slug - version properties: slug: type: string pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$' maxLength: 120 version: type: string pattern: '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$' maxLength: 120 repositoryProfileRevisionId: type: - string - 'null' format: uuid workMode: enum: - inspect - plan - guided - execute - recovery autonomyLevel: enum: - observe - diagnose - plan - implement - verify - repair inputs: $ref: '#/components/schemas/CompositionJsonObject' scopeOverrides: $ref: '#/components/schemas/CompositionScopeOverrides' outputFormat: description: Logical composition format. Artifact creation and download remain separate operations. enum: - prompt - markdown - run-pack default: prompt CompositionJsonValue: oneOf: - type: 'null' - type: boolean - type: number - type: string maxLength: 20000 - type: array maxItems: 100 items: $ref: '#/components/schemas/CompositionJsonValue' - $ref: '#/components/schemas/CompositionJsonObject' CompositionJsonObject: type: object maxProperties: 100 propertyNames: type: string minLength: 1 maxLength: 120 additionalProperties: $ref: '#/components/schemas/CompositionJsonValue' CompositionPath: type: string minLength: 1 maxLength: 500 pattern: '^(?!/)(?!.*\\\\)(?!.*(?:^|/)\.\.(?:/|$))[^\u0000-\u001f\u007f]+$' CompositionScopeOverrides: type: object additionalProperties: false properties: includedPaths: type: array maxItems: 100 uniqueItems: true items: $ref: '#/components/schemas/CompositionPath' excludedPaths: type: array maxItems: 100 uniqueItems: true items: $ref: '#/components/schemas/CompositionPath' allowableChangeTypes: type: array maxItems: 30 uniqueItems: true items: type: string pattern: '^[a-z][a-z0-9-]*$' maxLength: 80 repositoryWideRead: type: boolean CompositionPatchRequest: type: object additionalProperties: false minProperties: 1 properties: repositoryProfileRevisionId: type: - string - 'null' format: uuid workMode: enum: - inspect - plan - guided - execute - recovery autonomyLevel: enum: - observe - diagnose - plan - implement - verify - repair inputs: $ref: '#/components/schemas/CompositionJsonObject' scopeOverrides: $ref: '#/components/schemas/CompositionScopeOverrides' outputFormat: enum: - prompt - markdown - run-pack lastRenderDigest: type: - string - 'null' pattern: '^[a-f0-9]{64}$' CompositionDraft: type: object additionalProperties: false required: - id - revision - request - lastRenderDigest - createdAt - updatedAt properties: id: type: string format: uuid revision: type: integer minimum: 1 request: $ref: '#/components/schemas/CompositionRequest' lastRenderDigest: type: - string - 'null' pattern: '^[a-f0-9]{64}$' createdAt: type: string format: date-time updatedAt: type: string format: date-time LintFinding: type: object additionalProperties: false required: - ruleId - severity - message - source - controlPath properties: ruleId: type: string pattern: '^[a-z][a-z0-9._-]*$' maxLength: 120 severity: enum: - info - warning - error message: type: string minLength: 1 maxLength: 2000 source: enum: - platform-policy - playbook - repository-profile - user-input - composer controlPath: type: - string - 'null' maxLength: 240 CompatibilityFinding: type: object additionalProperties: false required: - code - severity - message - source - controlPath properties: code: type: string pattern: '^[a-z][a-z0-9._-]*$' maxLength: 120 severity: enum: - warning - error message: type: string minLength: 1 maxLength: 2000 source: enum: - playbook - repository-profile - platform controlPath: type: - string - 'null' maxLength: 240 capability: type: - string - 'null' maxLength: 120 CompositionCompatibility: type: object additionalProperties: false required: - status - findings properties: status: enum: - compatible - warning - incompatible - unknown findings: type: array maxItems: 200 items: $ref: '#/components/schemas/CompatibilityFinding' CompositionSource: type: object additionalProperties: false required: - type - reference properties: type: enum: - platform-policy - workspace-policy - repository-profile - playbook - user-input - inferred-default reference: type: string minLength: 1 maxLength: 240 ResolvedPolicy: type: object additionalProperties: false required: - id - value - source - nonOverridable properties: id: type: string pattern: '^[a-z][a-z0-9._-]*$' maxLength: 120 value: $ref: '#/components/schemas/CompositionJsonValue' source: $ref: '#/components/schemas/CompositionSource' nonOverridable: type: boolean ResolvedScope: type: object additionalProperties: false required: - includedPaths - excludedPaths - protectedPaths - allowableChangeTypes - repositoryWideRead properties: includedPaths: type: array maxItems: 200 uniqueItems: true items: $ref: '#/components/schemas/CompositionPath' excludedPaths: type: array maxItems: 200 uniqueItems: true items: $ref: '#/components/schemas/CompositionPath' protectedPaths: type: array maxItems: 200 uniqueItems: true items: $ref: '#/components/schemas/CompositionPath' allowableChangeTypes: type: array maxItems: 30 uniqueItems: true items: type: string pattern: '^[a-z][a-z0-9-]*$' maxLength: 80 repositoryWideRead: type: boolean CompositionBlock: type: object additionalProperties: false required: - id - heading - markdown properties: id: type: string pattern: '^[a-z][a-z0-9-]*$' maxLength: 120 heading: type: string minLength: 1 maxLength: 160 markdown: type: string maxLength: 500000 ProvenanceFactAccess: type: object additionalProperties: false required: - path - outcome properties: path: type: string pattern: '^(inputs|repository|composition|platform)(?:\.[A-Za-z][A-Za-z0-9_-]*)+$' maxLength: 240 outcome: enum: - resolved - missing - type-mismatch ProvenanceEntry: type: object additionalProperties: false required: - blockId - sources - controlPath - factAccesses properties: blockId: type: string pattern: '^[a-z][a-z0-9-]*$' maxLength: 120 sources: type: array minItems: 1 maxItems: 100 items: $ref: '#/components/schemas/CompositionSource' controlPath: type: - string - 'null' maxLength: 240 factAccesses: type: array maxItems: 100 items: $ref: '#/components/schemas/ProvenanceFactAccess' CompositionResult: type: object additionalProperties: false required: - normalizedInput - compatibility - resolvedPolicies - resolvedScope - blocks - renderedPrompt - renderDigest - lintFindings - exportReadiness - provenance properties: normalizedInput: $ref: '#/components/schemas/CompositionJsonObject' compatibility: $ref: '#/components/schemas/CompositionCompatibility' resolvedPolicies: type: array maxItems: 200 items: $ref: '#/components/schemas/ResolvedPolicy' resolvedScope: $ref: '#/components/schemas/ResolvedScope' blocks: type: array minItems: 1 maxItems: 20 items: $ref: '#/components/schemas/CompositionBlock' renderedPrompt: type: string minLength: 1 maxLength: 2000000 renderDigest: type: string pattern: '^[a-f0-9]{64}$' lintFindings: type: array maxItems: 500 items: $ref: '#/components/schemas/LintFinding' exportReadiness: enum: - ready - warning - blocked provenance: type: array maxItems: 500 items: $ref: '#/components/schemas/ProvenanceEntry' GeneratedRunSummary: type: object additionalProperties: false required: - id - playbookSlug - playbookVersion - playbookDigest - repositoryName - repositoryProfileRevision - repositoryProfileDigest - workMode - autonomyLevel - renderDigest - generatedAt properties: id: type: string format: uuid playbookSlug: type: string pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$' maxLength: 120 playbookVersion: type: string pattern: '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$' maxLength: 120 playbookDigest: type: string pattern: '^[a-f0-9]{64}$' repositoryName: type: - string - 'null' maxLength: 200 repositoryProfileRevision: type: - integer - 'null' minimum: 1 repositoryProfileDigest: type: - string - 'null' pattern: '^[a-f0-9]{64}$' workMode: enum: - inspect - plan - guided - execute - recovery autonomyLevel: enum: - observe - diagnose - plan - implement - verify - repair renderDigest: type: string pattern: '^[a-f0-9]{64}$' generatedAt: type: string format: date-time GeneratedRunPage: type: object additionalProperties: false required: - items - nextCursor properties: items: type: array maxItems: 100 items: $ref: '#/components/schemas/GeneratedRunSummary' nextCursor: type: - string - 'null' maxLength: 500 GeneratedRunSnapshots: type: object additionalProperties: false required: - playbook - repositoryProfile - normalizedInput - policy - provenance properties: playbook: $ref: '#/components/schemas/CompositionJsonObject' repositoryProfile: oneOf: - type: 'null' - $ref: '#/components/schemas/CompositionJsonObject' normalizedInput: $ref: '#/components/schemas/CompositionJsonObject' policy: $ref: '#/components/schemas/CompositionJsonObject' provenance: type: array maxItems: 500 items: $ref: '#/components/schemas/ProvenanceEntry' GeneratedRunDetail: type: object additionalProperties: false required: - id - playbookSlug - playbookVersion - playbookDigest - repositoryName - repositoryProfileRevision - repositoryProfileDigest - workMode - autonomyLevel - renderDigest - generatedAt - renderedPrompt - snapshots - lintFindings - provenance - artifacts properties: id: type: string format: uuid playbookSlug: type: string pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$' maxLength: 120 playbookVersion: type: string pattern: '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$' maxLength: 120 playbookDigest: type: string pattern: '^[a-f0-9]{64}$' repositoryName: type: - string - 'null' maxLength: 200 repositoryProfileRevision: type: - integer - 'null' minimum: 1 repositoryProfileDigest: type: - string - 'null' pattern: '^[a-f0-9]{64}$' workMode: enum: - inspect - plan - guided - execute - recovery autonomyLevel: enum: - observe - diagnose - plan - implement - verify - repair renderDigest: type: string pattern: '^[a-f0-9]{64}$' generatedAt: type: string format: date-time renderedPrompt: type: string minLength: 1 maxLength: 2000000 snapshots: $ref: '#/components/schemas/GeneratedRunSnapshots' lintFindings: type: array maxItems: 500 items: $ref: '#/components/schemas/LintFinding' provenance: type: array maxItems: 500 items: $ref: '#/components/schemas/ProvenanceEntry' artifacts: type: array maxItems: 100 items: $ref: '#/components/schemas/Artifact' Artifact: type: object additionalProperties: false required: - id - runId - type - filename - mediaType - sizeBytes - sha256 - createdAt - expiresAt - downloadUrl properties: id: type: string format: uuid runId: type: string format: uuid type: enum: - prompt_text - markdown - run_pack_zip - agents_suggestion - support_bundle filename: type: string minLength: 1 maxLength: 255 mediaType: type: string enum: - text/plain; charset=utf-8 - text/markdown; charset=utf-8 - application/zip sizeBytes: type: integer minimum: 0 maximum: 52428800 sha256: type: string pattern: '^[a-f0-9]{64}$' createdAt: type: string format: date-time expiresAt: type: - string - 'null' format: date-time downloadUrl: type: string pattern: ^/api/v1/artifacts/[0-9a-f-]+/download$ ArtifactCreateRequest: type: object additionalProperties: false required: - type properties: type: enum: - prompt_text - markdown - run_pack_zip - agents_suggestion VerifiedRunPackImport: type: object additionalProperties: false required: - runId - rootDirectory - archiveSha256 - manifestDigest - renderDigest - fileCount properties: runId: type: string format: uuid rootDirectory: type: string minLength: 1 maxLength: 500 archiveSha256: type: string pattern: '^[a-f0-9]{64}$' manifestDigest: type: string pattern: '^[a-f0-9]{64}$' renderDigest: type: string pattern: '^[a-f0-9]{64}$' fileCount: type: integer minimum: 1 maximum: 100 GiteaIntegrationCreateRequest: type: object additionalProperties: false required: - displayName - baseUrl - token properties: displayName: type: string minLength: 1 maxLength: 120 baseUrl: type: string format: uri maxLength: 2048 token: type: string minLength: 1 maxLength: 4096 writeOnly: true allowPrivateHttp: type: boolean default: false requestTimeoutMs: type: integer minimum: 1000 maximum: 60000 default: 15000 Integration: type: object additionalProperties: false required: - id - type - displayName - baseUrl - status - capabilities - healthCode - lastCheckedAt - secretLastFour properties: id: type: string format: uuid type: const: gitea displayName: type: string baseUrl: type: string format: uri status: enum: - configured - healthy - degraded - disabled capabilities: type: object additionalProperties: $ref: '#/components/schemas/ForgeCapabilityState' serverVersion: type: - string - 'null' maxLength: 100 remoteIdentity: type: - object - 'null' additionalProperties: false properties: id: type: string maxLength: 100 login: type: string maxLength: 255 healthCode: oneOf: - $ref: '#/components/schemas/GiteaSafeErrorCode' - type: 'null' lastCheckedAt: type: - string - 'null' format: date-time secretLastFour: type: - string - 'null' IntegrationTestResult: type: object additionalProperties: false required: - status - capabilities - healthCode - warnings properties: status: enum: - healthy - degraded - failed serverVersion: type: - string - 'null' capabilities: type: object additionalProperties: $ref: '#/components/schemas/ForgeCapabilityState' healthCode: oneOf: - $ref: '#/components/schemas/GiteaSafeErrorCode' - type: 'null' warnings: type: array items: type: string ExternalRepositoryPage: type: object additionalProperties: false required: - items - nextCursor properties: items: type: array items: type: object required: - externalId - owner - name properties: externalId: type: string owner: type: string name: type: string defaultBranch: type: - string - 'null' archived: type: boolean private: type: boolean permissions: type: object additionalProperties: false properties: pull: type: boolean push: type: boolean admin: type: boolean nextCursor: type: - string - 'null' SecretRotationRequest: type: object additionalProperties: false required: - token properties: token: type: string minLength: 1 maxLength: 4096 writeOnly: true ForgeCapabilityState: type: string enum: - supported - unsupported - forbidden - temporarily_unavailable GiteaSafeErrorCode: type: string enum: - AUTH_INVALID - PERMISSION_MISSING - CAPABILITY_UNSUPPORTED - RATE_LIMITED - NETWORK_BLOCKED - TLS_ERROR - REMOTE_UNAVAILABLE - CONTENT_TOO_LARGE GiteaRepositoryImportRequest: type: object additionalProperties: false required: - externalId properties: externalId: type: string minLength: 1 maxLength: 255 GiteaRepositoryImportResult: type: object additionalProperties: false required: - repositoryId - snapshotId - jobId properties: repositoryId: type: string format: uuid snapshotId: type: string format: uuid jobId: type: string format: uuid JobReference: type: object required: - jobId properties: jobId: type: string format: uuid Job: type: object required: - id - type - state - attemptCount - maxAttempts - retryable - createdAt properties: id: type: string format: uuid type: type: string state: enum: - queued - running - succeeded - failed - cancelled progress: type: object additionalProperties: true attemptCount: type: integer maxAttempts: type: integer errorCode: type: - string - 'null' errorDetail: type: - string - 'null' retryable: type: boolean createdAt: type: string format: date-time updatedAt: type: string format: date-time JobPage: type: object required: - items - nextCursor properties: items: type: array items: $ref: '#/components/schemas/Job' nextCursor: type: - string - 'null' AuditEvent: type: object required: - id - occurredAt - action - resourceType - outcome properties: id: type: string format: uuid occurredAt: type: string format: date-time actorUserId: type: - string - 'null' format: uuid workspaceId: type: - string - 'null' format: uuid action: type: string resourceType: type: string resourceId: type: - string - 'null' outcome: enum: - success - denied - failed metadata: type: object additionalProperties: true AuditEventPage: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/AuditEvent' nextCursor: type: - string - 'null' InstanceConfig: type: object description: Validated non-secret InstanceConfig document additionalProperties: true HealthStatus: type: object required: - status properties: status: enum: - alive - ready - not-ready - degraded checks: type: array items: type: object required: - name - status properties: name: type: string status: enum: - ok - degraded - failed code: type: - string - 'null' version: type: string schemaVersion: type: string responses: NotFoundResponse: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/Error' UnauthorizedResponse: description: Authentication required or invalid content: application/json: schema: $ref: '#/components/schemas/Error' ForbiddenResponse: description: Actor lacks permission content: application/json: schema: $ref: '#/components/schemas/Error' ConflictResponse: description: Resource state or idempotency conflict content: application/json: schema: $ref: '#/components/schemas/Error' PreconditionRequiredResponse: description: A required optimistic-concurrency precondition was not supplied content: application/json: schema: $ref: '#/components/schemas/Error' ValidationResponse: description: Validation failed content: application/json: schema: $ref: '#/components/schemas/Error' PayloadTooLargeResponse: description: Request or expanded archive exceeds limits content: application/json: schema: $ref: '#/components/schemas/Error' RateLimitedResponse: description: Rate limit exceeded headers: Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/Error' ServiceUnavailableResponse: description: A required service is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error'