# Published documentation view of api/openapi/openapi.yaml. Do not edit by hand; run 'make docs-openapi' after changing the canonical spec.
openapi: 3.1.2
info:
  title: Omnara API
  version: 0.1.0
  description: Public HTTP API contract for Omnara.
servers:
  - url: https://api.omnara.com/v1
    description: Hosted Omnara
  - url: /api/v1
    description: Self-hosted Omnara, relative to the deployment origin
security:
  - bearerAuth: []
  - browserSessionCookie: []
tags:
  - name: Agents
    description: Launch agents, send inputs, manage the input backlog, and work with tool calls.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/agents/overview
  - name: Interactions
    description: List and resolve the approvals and questions that pause an agent.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/events/interactions
  - name: Actors
    description: Attribute agent inputs and interaction responses to external users.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/events/sending-input#who-said-that-actors-and-attribution
  - name: Events
    description: Read or stream the agent timeline, list turns, and download artifacts.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/events/streaming
  - name: Configs and Profiles
    description: Create agent configs, manage reusable launch profiles, and set up integrations.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/agents/configuration
  - name: Models
    description: Configure model providers and models, and grant projects access to them.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/organization/model-providers
  - name: Machines
    description: Register machines, control project access, and manage daemon tokens.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/machines/connect
  - name: Machine Pools
    description: Define machine pools and grant projects access to them.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/machines/pools
  - name: Secrets
    description: Manage secret ownership and versions, and inspect or grant project availability.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/organization/secrets
  - name: Skills
    description: Manage versioned skill ownership and load skill instructions on demand.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/tools/skills
  - name: Organizations and Projects
    description: Create organizations and projects and manage membership.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/organization/members
  - name: Users and API Keys
    description: The authenticated user, personal and organization API keys, and invitations.
    externalDocs:
      description: Guide
      url: https://docs.omnara.com/api/authentication
  - name: Machine Daemon
    description: Routes the Omnara machine daemon uses to connect a machine.
paths:
  /personal-access-tokens:
    get:
      operationId: listPersonalAccessTokens
      tags: [Users and API Keys]
      summary: List the authenticated user's personal access tokens
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: The authenticated user's personal access tokens.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListPersonalAccessTokensResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createPersonalAccessToken
      tags: [Users and API Keys]
      summary: Create personal access token
      security:
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePersonalAccessTokenRequest'
      responses:
        '201':
          description: Personal access token created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreatePersonalAccessTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /personal-access-tokens/{tokenID}/revoke:
    parameters:
      - name: tokenID
        in: path
        required: true
        schema:
          type: string
          pattern: '^pat_[a-z2-7]{26}$'
    post:
      operationId: revokePersonalAccessToken
      tags: [Users and API Keys]
      summary: Revoke a personal access token
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: The revoked personal access token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PersonalAccessToken'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/bootstrap:
    post:
      operationId: bootstrapDaemon
      x-hidden: true
      tags: [Machine Daemon]
      summary: Bootstrap daemon
      security:
        - machineDaemonAuth: []
      responses:
        '200':
          description: Machine daemon bootstrap information.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BootstrapDaemonResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/failures:
    post:
      operationId: recordMachineFailure
      x-hidden: true
      tags: [Machine Daemon]
      summary: Record machine failure
      security:
        - machineDaemonAuth: []
      parameters:
        - name: stage
          in: query
          required: true
          schema:
            type: string
            enum: [startup_script, daemon_install, daemon_update, daemon_uninstall, daemon_uninstalled]
        - name: exit_status
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 255
        - name: capture_status
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            maximum: 255
        - name: daemon_version
          in: query
          required: false
          schema:
            type: string
            maxLength: 100
        - name: target_version
          in: query
          required: false
          schema:
            type: string
            maxLength: 100
      requestBody:
        content:
          text/plain:
            schema:
              type: string
              maxLength: 4097
      responses:
        '204':
          description: Machine failure recorded.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs:
    post:
      operationId: createOrganization
      tags: [Organizations and Projects]
      summary: Create organization
      description: |
        Creates the organization and its local default resources atomically.
        An idempotency key determines the proposed organization ID; replaying it
        returns the existing organization. Without a key, each request is a fresh
        attempt. Optional default-provider provisioning begins after commit and
        retries asynchronously without failing organization creation.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrganizationRequest'
      responses:
        '201':
          description: Organization created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateOrganizationResponse'
        '200':
          description: Idempotent replay of an existing organization creation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateOrganizationResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    delete:
      operationId: deleteOrganization
      tags: [Organizations and Projects]
      summary: Delete organization
      description: >-
        Deletes the organization and everything in it: projects, memberships, pending invitations,
        profiles, integrations, machine pools and machines, model provider configs and configured
        models, and all skills. Agents are archived and their runtimes and queued work are stopped.
        Secrets are permanently deleted once machine teardown no longer needs them. Deletion fails if
        project agent teardown cannot complete. Only organization owners can delete an organization.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Organization deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /me:
    get:
      operationId: getCurrentUser
      tags: [Users and API Keys]
      summary: Get the authenticated user and their organizations
      responses:
        '200':
          description: The authenticated user and the organizations they belong to.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CurrentUser'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteCurrentUser
      tags: [Users and API Keys]
      summary: Delete the authenticated user's account
      description: >-
        Deletes the account, revokes all personal access tokens and browser sessions, removes all
        organization and project memberships, and releases the account's sign-in identity
        (emails, linked auth identities, and password credentials) so the same email can register a
        new account. Personal secrets and skills owned by the user are deleted with the account.
        Deletion is blocked while the user is the last owner of any organization (add another owner
        or delete the organization first), while a personal skill is referenced by an active
        agent's configuration, or while a personal secret is referenced by a model provider config,
        machine pool, or integration install. Organization and project resources are unaffected,
        and agents, machines, and other records the user created are kept with their attribution.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Account deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /invitations:
    get:
      operationId: listPendingInvitations
      tags: [Users and API Keys]
      summary: List pending invitations
      description: Items are ordered by created_at ascending, then id ascending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Pending organization invitations for the authenticated user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListOrgInvitationsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /invitations/{invitationID}/accept:
    parameters:
      - name: invitationID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oinv_[a-z2-7]{26}$'
    post:
      operationId: acceptInvitation
      tags: [Users and API Keys]
      summary: Accept invitation
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: The accepted invitation; accepting consumes it and creates the membership.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgInvitation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /invitations/{invitationID}/decline:
    parameters:
      - name: invitationID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oinv_[a-z2-7]{26}$'
    post:
      operationId: declineInvitation
      tags: [Users and API Keys]
      summary: Decline invitation
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: The declined invitation; declining consumes it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgInvitation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/overview:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/OrganizationID'
    get:
      operationId: getOrgOverview
      x-hidden: true
      tags: [Organizations and Projects]
      summary: Get org overview
      description: >-
        Returns the data backing the web app's overview page: the caller's visible
        projects plus the most recently active agents and most recently updated
        agent profiles across every project the caller can read. Internal to the
        web app and subject to change without notice.
      responses:
        '200':
          description: Overview data for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgOverviewResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: createProject
      tags: [Organizations and Projects]
      summary: Create project
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProjectRequest'
      responses:
        '201':
          description: Project created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Project'
        '200':
          description: Idempotent replay of an existing project creation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Project'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listVisibleProjects
      tags: [Organizations and Projects]
      summary: List visible projects
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Projects visible to the authenticated user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    delete:
      operationId: deleteProject
      tags: [Organizations and Projects]
      summary: Delete project
      description: >-
        Deletes the project, its memberships, profiles and profile versions, integration installs
        and targets, project-owned skills and revisions, and grants owned by or targeting the
        project. Project-owned secrets are permanently deleted with their versions and
        grants. The project's agents are archived and their runtimes and queued work are stopped.
        Machine, machine-pool, and model grants are removed without deleting the shared machine, pool,
        or model. Deletion fails if agent teardown cannot complete.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/members:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    get:
      operationId: listOrgMembers
      tags: [Organizations and Projects]
      summary: List organization members
      description: List organization members with server-side display-name filtering, sorting, and cursor pagination.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/CreatedResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Members of the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListOrgMembersResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/members/{userID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: userID
        in: path
        required: true
        schema:
          type: string
          pattern: '^usr_[a-z2-7]{26}$'
    patch:
      operationId: updateOrgMember
      tags: [Organizations and Projects]
      summary: Update org member role
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrgMemberRequest'
      responses:
        '200':
          description: Org member role updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationMembership'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: removeOrgMember
      tags: [Organizations and Projects]
      summary: Remove org member
      description: >-
        Removes the user's organization membership and all project memberships in the
        organization. The member's personal secrets and skills in the organization are deleted with
        the membership. Removal is blocked when the user is the organization's last owner, while a
        personal skill is referenced by an active agent's configuration, or while a personal secret
        is referenced by a model provider config, machine pool, or integration install.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Org member removed.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/members/{userID}/projects:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: userID
        in: path
        required: true
        schema:
          type: string
          pattern: '^usr_[a-z2-7]{26}$'
    get:
      operationId: listMemberProjectAccess
      tags: [Organizations and Projects]
      summary: List a member's explicit project role grants
      description: >-
        Lists the member's explicit per-project role grants. Org owners and
        admins implicitly have admin access to every project and will not
        appear here for those projects.
      responses:
        '200':
          description: The member's explicit project role grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectMembershipGrantsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/members/{userID}/projects/{projectID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: userID
        in: path
        required: true
        schema:
          type: string
          pattern: '^usr_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    put:
      operationId: setMemberProjectAccess
      tags: [Organizations and Projects]
      summary: Set a member's role on a project
      description: Creates or updates the member's explicit role grant on the project.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetProjectMembershipRequest'
      responses:
        '200':
          description: Project role grant set.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMembershipGrant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: removeMemberProjectAccess
      tags: [Organizations and Projects]
      summary: Remove a member's project role grant
      description: >-
        Removes only the member's explicit role grant for this project. No other memberships, grants,
        or resources are deleted, and there are no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project role grant removed.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/api-keys:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    get:
      operationId: listOrgAPIKeys
      tags: [Users and API Keys]
      summary: List org API keys
      description: Items are ordered by created_at descending, then id descending. Revoked keys are included.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: The organization's API keys.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListOrgAPIKeysResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createOrgAPIKey
      tags: [Users and API Keys]
      summary: Create org API key
      description: Mints an org API key. The plaintext token is returned once and never stored.
      security:
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrgAPIKeyRequest'
      responses:
        '201':
          description: Org API key created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateOrgAPIKeyResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/api-keys/{keyID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: keyID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oak_[a-z2-7]{26}$'
    get:
      operationId: getOrgAPIKey
      tags: [Users and API Keys]
      summary: Get an org API key
      responses:
        '200':
          description: The org API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgAPIKey'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateOrgAPIKey
      tags: [Users and API Keys]
      summary: Update an org API key
      description: Renames the key and/or changes its org role. Revoked keys cannot be updated.
      security:
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrgAPIKeyRequest'
      responses:
        '200':
          description: The updated org API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgAPIKey'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/api-keys/{keyID}/revoke:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: keyID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oak_[a-z2-7]{26}$'
    post:
      operationId: revokeOrgAPIKey
      tags: [Users and API Keys]
      summary: Revoke an org API key
      description: Terminally revokes the key and removes its org and project roles. Idempotent.
      security:
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: The revoked org API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgAPIKey'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/api-keys/{keyID}/projects:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: keyID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oak_[a-z2-7]{26}$'
    get:
      operationId: listOrgAPIKeyProjectAccess
      tags: [Users and API Keys]
      summary: List an org API key's explicit project role grants
      description: >-
        Lists the key's explicit per-project role grants. Keys with the admin
        org role implicitly have admin access to every project and will not
        appear here for those projects.
      responses:
        '200':
          description: The key's explicit project role grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectMembershipGrantsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/api-keys/{keyID}/projects/{projectID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: keyID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oak_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    put:
      operationId: setOrgAPIKeyProjectRole
      tags: [Users and API Keys]
      summary: Set an org API key's role on a project
      description: Creates or updates the key's explicit role grant on the project.
      security:
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetProjectMembershipRequest'
      responses:
        '200':
          description: Project role grant set.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMembershipGrant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: removeOrgAPIKeyProjectRole
      tags: [Users and API Keys]
      summary: Remove an org API key's project role grant
      security:
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project role grant removed.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/invitations:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    get:
      operationId: listOrgInvitations
      tags: [Organizations and Projects]
      summary: List org invitations
      description: >-
        Every listed invitation is pending: accepting, declining, revoking, or organization deletion
        removes the invitation. Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Organization invitations.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListOrgInvitationsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createOrgInvitation
      tags: [Organizations and Projects]
      summary: Create org invitation
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrgInvitationRequest'
      responses:
        '201':
          description: Organization invitation created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgInvitation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/invitations/{invitationID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: invitationID
        in: path
        required: true
        schema:
          type: string
          pattern: '^oinv_[a-z2-7]{26}$'
    delete:
      operationId: deleteOrgInvitation
      tags: [Organizations and Projects]
      summary: Delete org invitation
      description: Deletes the pending invitation so it can no longer be accepted.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Organization invitation deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/skills:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: createSkill
      tags: [Skills]
      summary: Create skill
      description: >-
        Uploads a skill archive. If a skill with the archive's name already
        exists for the requested owner, the upload becomes the skill's next
        revision. The owner is immutable after creation.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateSkillRequest'
            encoding:
              owner:
                contentType: application/json
      responses:
        '201':
          description: Skill created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Skill'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '413':
          description: The uploaded skill archive is too large.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listSkills
      tags: [Skills]
      summary: List skills visible through ownership authority
      description: Items are ordered by created_at descending, then id descending. Without an owner filter, returns the deduplicated union of organization skills the caller may list, project skills the caller may list, and the caller's own user skills. Grants are managed separately and do not change ownership.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/SkillOwnerKindFilter'
        - $ref: '#/components/parameters/SkillOwnerProjectIDFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Skills visible through ownership authority.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSkillsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/skills/{skillID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: skillID
        in: path
        required: true
        schema:
          type: string
          pattern: '^skl_[a-z2-7]{26}$'
    get:
      operationId: getSkill
      tags: [Skills]
      summary: Get skill through ownership authority
      responses:
        '200':
          description: Visible skill metadata, instructions, and archive file listing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Skill'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: updateSkill
      tags: [Skills]
      summary: Update skill by uploading a new revision
      description: >-
        Creates the skill's next revision from either a replacement archive or
        replacement SKILL.md content (which keeps every other file from the
        current revision). The SKILL.md frontmatter `name` must match the
        skill's existing name.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/UpdateSkillRequest'
      responses:
        '200':
          description: Skill updated with a new revision.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Skill'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '413':
          description: The uploaded skill archive is too large.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteSkill
      tags: [Skills]
      summary: Delete skill
      description: >-
        Deletes the skill together with all of its revisions and project grants; uploaded archive
        content is destroyed. No other resources are deleted. Deletion is blocked while an active
        agent's configuration references the skill.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Skill deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/skills/{skillID}/grants:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: skillID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/SkillID'
    get:
      operationId: listSkillGrants
      tags: [Skills]
      summary: List skill grants
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/CreatedResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Outgoing skill grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSkillGrantsResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createSkillGrant
      tags: [Skills]
      summary: Create skill grant
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SkillGrantCreateRequest'
      responses:
        '201':
          description: Skill grant created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SkillGrant'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/skills/{skillID}/grants/{grantID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: skillID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/SkillID'
      - name: grantID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/SkillGrantID'
    delete:
      operationId: deleteSkillGrant
      tags: [Skills]
      summary: Delete skill grant
      description: >-
        Deletes only this project grant. The skill, its revisions, the target project, and other grants
        are retained, and there are no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Skill grant deleted.
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/skills:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ProjectID'
    get:
      operationId: listProjectAvailableSkills
      tags: [Skills]
      summary: List skills available to project
      description: Includes directly owned project skills and granted skills, ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/SkillOwnerKindFilter'
        - $ref: '#/components/parameters/SkillAvailabilitySourceFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Skills available to the project with their availability source.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectSkillAccessesResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    get:
      operationId: listSecrets
      tags: [Secrets]
      summary: List secrets visible through ownership authority
      description: Items are ordered by created_at descending, then id descending. Without an owner filter, returns the deduplicated union of organization secrets the caller may list, project secrets the caller may list, and the caller's own user secrets.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/SecretKindFilter'
        - $ref: '#/components/parameters/SecretOwnerKindFilter'
        - $ref: '#/components/parameters/SecretOwnerProjectIDFilter'
        - $ref: '#/components/parameters/SecretMCPOAuthFlowIDFilter'
        - $ref: '#/components/parameters/SecretMetadataFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Secrets visible through ownership authority.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSecretsResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createSecret
      tags: [Secrets]
      summary: Create secret
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSecretRequest'
      responses:
        '201':
          description: Secret created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Secret'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets/mcp-oauth:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: startSecretMCPOAuth
      tags: [Secrets]
      summary: Start MCP OAuth for a new secret
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MCPOAuthStartRequest'
      responses:
        '201':
          description: MCP OAuth flow started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MCPOAuthStartResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '422': { $ref: '#/components/responses/UnprocessableEntity' }
        '502': { $ref: '#/components/responses/BadGateway' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets/{secretID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: secretID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sec_[a-z2-7]{26}$'
    get:
      operationId: getSecret
      tags: [Secrets]
      summary: Get secret through ownership authority
      responses:
        '200':
          description: Secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Secret'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateSecret
      tags: [Secrets]
      summary: Update secret metadata
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSecretRequest'
      responses:
        '200':
          description: Secret updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Secret'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteSecret
      tags: [Secrets]
      summary: Delete secret
      description: >-
        Deletes the secret and permanently destroys all of its versions and project grants; the
        ciphertext cannot be recovered. Deletion is blocked while the secret is referenced by a
        model provider config, machine pool, or integration install.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Secret deleted.
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets/{secretID}/versions:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: secretID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sec_[a-z2-7]{26}$'
    post:
      operationId: createSecretVersion
      tags: [Secrets]
      summary: Create secret version
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SecretVersionRequest'
      responses:
        '200':
          description: Secret version created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Secret'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets/{secretID}/grants:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: secretID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sec_[a-z2-7]{26}$'
    get:
      operationId: listSecretGrants
      tags: [Secrets]
      summary: List secret grants
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/CreatedResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Outgoing secret grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSecretGrantsResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    post:
      operationId: createSecretGrant
      tags: [Secrets]
      summary: Create secret grant
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SecretGrantCreateRequest'
      responses:
        '201':
          description: Secret grant created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretGrant'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { $ref: '#/components/responses/Conflict' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/secrets/{secretID}/grants/{grantID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: secretID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sec_[a-z2-7]{26}$'
      - name: grantID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sgr_[a-z2-7]{26}$'
    delete:
      operationId: deleteSecretGrant
      tags: [Secrets]
      summary: Delete secret grant
      description: >-
        Deletes only this project grant. The secret, its versions, the target project, and other grants
        are retained, and there are no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Secret grant deleted.
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/integration-installs:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    get:
      operationId: listIntegrationInstalls
      tags: [Configs and Profiles]
      summary: List integration installs
      description: >-
        Items are ordered by created_at descending, then id descending. The list's logical name is
        provider_agent_display_name.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/IntegrationInstallAgentProfileFilter'
        - $ref: '#/components/parameters/IntegrationInstallOAuthFlowIDFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Integration installs in the project, newest first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListIntegrationInstallsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/integration-installs/{integrationInstallID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: integrationInstallID
        in: path
        required: true
        schema:
          type: string
          pattern: '^iin_[a-z2-7]{26}$'
    delete:
      operationId: deleteIntegrationInstall
      tags: [Configs and Profiles]
      summary: Delete integration install
      description: >-
        Deletes the install and all of its integration targets and clears those target associations from
        agents. Agents and profiles are retained. This uninstalls on the Omnara side only: credentials
        already issued by the provider are not revoked and provider-side webhooks are not removed.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Integration install deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-configs:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createAgentConfig
      tags: [Configs and Profiles]
      summary: Create agent config
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentConfigRequest'
      responses:
        '200':
          description: Existing agent config returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentConfig'
        '201':
          description: Agent config created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentConfig'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /tool-catalog:
    get:
      operationId: getToolCatalog
      tags: [Configs and Profiles]
      summary: Get tool catalog
      responses:
        '200':
          description: Built-in tools and permission modes available to agent configs.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolCatalog'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /mcp-servers:
    get:
      operationId: listMCPServers
      tags: [Configs and Profiles]
      summary: Search the MCP server registry
      description: Search the API's snapshot of the public MCP registry. The snapshot only holds active servers that publish a `streamable-http` remote. Results are ranked by relevance when `q` is set, otherwise ordered by name.
      parameters:
        - name: q
          in: query
          required: false
          schema:
            type: string
            maxLength: 200
          description: Free-text query matched against server name, title, description, and remote URLs. Each term matches as a prefix.
        - name: remote_url
          in: query
          required: false
          schema:
            type: string
            maxLength: 2048
          description: Only return servers with a remote at exactly this URL. Matching is case-insensitive and ignores the scheme and trailing slashes, so `MCP.linear.app/mcp/` matches `https://mcp.linear.app/mcp`.
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Registry servers matching the query.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListMCPServersResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/mcp-servers/tools:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/OrganizationID'
      - name: projectID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ProjectID'
    post:
      operationId: listMCPServerTools
      tags: [Configs and Profiles]
      summary: List an MCP server's tools
      description: Connects to a remote MCP server over streamable HTTP, completes the initialize handshake, and returns the server's `tools/list` result. The request is not stored; use it to preview which tools a server exposes before referencing it from an agent config. Authentication mirrors the agent config `mcp_servers.<key>.auth` shape and resolves secrets available to the project. When the server rejects the connection with HTTP 401 or 403, the API probes the server's authorization requirements and responds 422 with an `auth` hint — `oauth` when the server advertises an OAuth authorization server, `bearer` when it expects a token but advertises no OAuth metadata.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MCPServerToolsRequest'
      responses:
        '200':
          description: Tools advertised by the MCP server.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MCPServerToolsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: The MCP server rejected the configured authentication. `auth` hints which auth type the server expects.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MCPServerAuthRequiredError'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-configs/{agentConfigID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentConfigID
        in: path
        required: true
        schema:
          type: string
          pattern: '^acfg_[a-z2-7]{26}$'
    get:
      operationId: getAgentConfig
      tags: [Configs and Profiles]
      summary: Get agent config
      responses:
        '200':
          description: Agent config.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentConfig'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-profiles:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createAgentProfile
      tags: [Configs and Profiles]
      summary: Create agent profile
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentProfileRequest'
      responses:
        '200':
          description: Existing agent profile returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfile'
        '201':
          description: Agent profile created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfile'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listAgentProfiles
      tags: [Configs and Profiles]
      summary: List agent profiles
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Agent profiles in the project, newest first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentProfilesResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-profiles/{agentProfileID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentProfileID
        in: path
        required: true
        schema:
          type: string
          pattern: '^aprf_[a-z2-7]{26}$'
    get:
      operationId: getAgentProfile
      tags: [Configs and Profiles]
      summary: Get agent profile
      responses:
        '200':
          description: Agent profile.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfile'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: renameAgentProfile
      tags: [Configs and Profiles]
      summary: Rename agent profile
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RenameAgentProfileRequest'
      responses:
        '200':
          description: Agent profile renamed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfile'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteAgentProfile
      tags: [Configs and Profiles]
      summary: Delete agent profile
      description: >-
        Deletes the profile, all of its profile versions, and any cron triggers targeting the
        profile. Agents launched from the profile are retained and keep running: each agent holds an
        immutable snapshot of the configuration it was launched with, so its reference to the profile
        becomes historical provenance only. Deletion is blocked while an active integration install
        references the profile.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-profiles/{agentProfileID}/config:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentProfileID
        in: path
        required: true
        schema:
          type: string
          pattern: '^aprf_[a-z2-7]{26}$'
    post:
      operationId: updateAgentProfile
      tags: [Configs and Profiles]
      summary: Update agent profile
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAgentProfileRequest'
      responses:
        '200':
          description: Agent profile updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfile'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-profiles/{agentProfileID}/integration-oauth/setup:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentProfileID
        in: path
        required: true
        schema:
          type: string
          pattern: '^aprf_[a-z2-7]{26}$'
    post:
      operationId: createIntegrationOAuthSetup
      tags: [Configs and Profiles]
      summary: Create integration OAuth setup
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateIntegrationOAuthSetupRequest'
      responses:
        '201':
          description: Integration OAuth setup created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationOAuthSetup'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agent-profiles/{agentProfileID}/slack-setup:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentProfileID
        in: path
        required: true
        schema:
          type: string
          pattern: '^aprf_[a-z2-7]{26}$'
    post:
      operationId: createSlackSetup
      tags: [Configs and Profiles]
      summary: Create Slack app and OAuth setup
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSlackSetupRequest'
      responses:
        '201':
          description: Slack app created and OAuth setup started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SlackSetup'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/cron-triggers:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createCronTrigger
      tags: [Configs and Profiles]
      summary: Create cron trigger
      description: >-
        Creates a cron trigger that fires on a schedule. A trigger targeting an agent profile
        launches a new agent from the profile's current config on each firing; a trigger targeting
        an agent sends an input to that agent. Missed firings are coalesced, matching standard
        cron behavior: if one or more scheduled times pass while firing is delayed, the trigger
        fires once for the oldest missed time and then resumes its schedule from the current time,
        without retroactively firing for the other missed times.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCronTriggerRequest'
      responses:
        '200':
          description: Existing cron trigger returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CronTrigger'
        '201':
          description: Cron trigger created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CronTrigger'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listCronTriggers
      tags: [Configs and Profiles]
      summary: List cron triggers
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: agent_id
          in: query
          description: Only return triggers targeting this agent.
          schema:
            $ref: '#/components/schemas/AgentID'
        - name: agent_profile_id
          in: query
          description: Only return triggers targeting this agent profile.
          schema:
            $ref: '#/components/schemas/AgentProfileID'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Cron triggers in the project, newest first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListCronTriggersResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/cron-triggers/{cronTriggerID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: cronTriggerID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/CronTriggerID'
    get:
      operationId: getCronTrigger
      tags: [Configs and Profiles]
      summary: Get cron trigger
      responses:
        '200':
          description: Cron trigger.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CronTrigger'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateCronTrigger
      tags: [Configs and Profiles]
      summary: Update cron trigger
      description: >-
        Updates the schedule, message template, or enabled state. The target is immutable; delete
        the trigger and create a new one to retarget.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCronTriggerRequest'
      responses:
        '200':
          description: Cron trigger updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CronTrigger'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteCronTrigger
      tags: [Configs and Profiles]
      summary: Delete cron trigger
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createAgent
      tags: [Agents]
      summary: Create agent
      description: Reusing an idempotency key returns the current agent even if the retry body differs. The retry body is not applied.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentRequest'
      responses:
        '200':
          description: Current state of the previously created agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CurrentAgentResponse'
        '201':
          description: Agent launched.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LaunchAgentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The launch conflicts with current resource state for a reason other than a changed retry body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listAgents
      tags: [Agents]
      summary: List agents
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: agent_profile_id
          in: query
          description: Return only agents launched from this agent profile.
          schema:
            $ref: '#/components/schemas/AgentProfileID'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Active agents in the project, newest first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: getAgent
      tags: [Agents]
      summary: Get agent
      responses:
        '200':
          description: Agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetAgentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/archive:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    post:
      operationId: archiveAgent
      tags: [Agents]
      summary: Archive agent
      description: >-
        Archives the agent: requests cancellation of its active runtime, cancels queued inputs and
        affected processes, removes its pending wakeup, releases explicit machine bindings, deletes
        pooled machines created for the agent, and deletes cron triggers targeting the agent. The
        agent and its full event history stay readable by id; archived agents leave listings. The agent's profile and configuration are retained, as are
        explicitly attached BYO machines. Archiving an already-archived agent is a no-op that returns
        the agent unchanged.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: The archived agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CurrentAgentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/config:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    post:
      operationId: updateAgentConfig
      tags: [Agents]
      summary: Update agent config
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAgentConfigRequest'
      responses:
        '200':
          description: Agent config updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateAgentConfigResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    post:
      operationId: createAgentInput
      tags: [Agents]
      summary: Create agent input
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentInputRequest'
      responses:
        '200':
          description: Existing agent input returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentInputEnvelope'
        '201':
          description: Agent input created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentInputEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/tool-calls:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: listToolCalls
      tags: [Agents]
      summary: List tool calls
      description: Items are ordered by created_at ascending, then id ascending.
      parameters:
        - name: state
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/ToolCallState'
        - name: type
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/ToolCallType'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Current tool calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListToolCallsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/tool-calls/{toolCallID}/result:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: toolCallID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ToolCallID'
    post:
      operationId: submitToolCallResult
      tags: [Agents]
      summary: Submit a result for a ready custom tool call
      description: >-
        Only ready custom tool calls accept externally supplied results.
        The first accepted result completes the call. Any later submission,
        or a result for a non-custom tool call, returns 409.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitToolCallResultRequest'
      responses:
        '201':
          description: Custom tool result accepted and tool call completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmitToolCallResultResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/turns:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: listTurns
      tags: [Events]
      summary: List turns
      description: Returns turns newest first. Use the returned next_before_turn_sequence as before_turn_sequence to fetch older turns.
      parameters:
        - name: before_turn_sequence
          in: query
          required: false
          description: Exclusive turn sequence boundary. Omit or pass 0 for the newest turns.
          schema:
            type: integer
            format: int64
            minimum: 0
        - name: limit
          in: query
          required: false
          description: Maximum number of turns to return.
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 25
      responses:
        '200':
          description: Agent turns.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentTurnsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/turns/{turnID}/events:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: turnID
        in: path
        required: true
        schema:
          type: string
          pattern: '^trn_[a-z2-7]{26}$'
    get:
      operationId: listTurnEvents
      tags: [Events]
      summary: List turn events
      description: Returns one older event page for a turn, ordered chronologically within the page. Use the returned next_before_sequence as before_sequence to fetch older events.
      parameters:
        - name: before_sequence
          in: query
          required: false
          description: Exclusive event sequence boundary. Omit or pass 0 for the latest events in the turn.
          schema:
            type: integer
            format: int64
            minimum: 0
        - name: limit
          in: query
          required: false
          description: Maximum number of events to return.
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 500
            default: 100
      responses:
        '200':
          description: Turn events.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListTurnEventsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/events:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: listEvents
      tags: [Events]
      summary: List events
      description: >-
        Returns one page of agent events, chronological within the page.
        Forward pagination (after_sequence) walks from a known boundary toward
        the present using next_after_sequence. Backward pagination
        (before_sequence) starts at the latest events and walks toward the
        beginning using next_before_sequence; passing before_sequence takes
        precedence over after_sequence.
      parameters:
        - name: before_sequence
          in: query
          required: false
          description: Exclusive event sequence boundary for backward pagination. Pass 0 for the latest events.
          schema:
            type: integer
            format: int64
            minimum: 0
        - name: after_sequence
          in: query
          required: false
          description: Exclusive event sequence boundary. Omit or pass 0 for the beginning of the agent event log.
          schema:
            type: integer
            format: int64
            minimum: 0
        - name: limit
          in: query
          required: false
          description: Maximum number of events to return.
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 500
            default: 100
      responses:
        '200':
          description: Agent events.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentEventsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/events/stream:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: streamEvents
      tags: [Events]
      summary: Stream events
      parameters:
        - name: after_sequence
          in: query
          required: false
          schema:
            type: integer
            format: int64
            minimum: 0
        - name: stream_deltas
          in: query
          required: false
          description: >-
            Opt in to ephemeral delta streamed frames while a model call is in
            flight. This includes partial assistant text, tool call, and
            reasoning output. Each frame carries the public `turn_id` and
            `model_call_context_id` it belongs to, and `tool_use` block starts
            carry the same public `tool_call_id` the durable `model_output`
            content block and `tool_result` event will use. Deltas are
            best-effort: they are not persisted and are not replayed on
            reconnect. The durable `model_output` event remains the source of
            truth. Default false.
          schema:
            type: boolean
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: integer
            format: int64
            minimum: 0
      responses:
        '200':
          description: >-
            Server-sent event stream. Durable frames use `agent_input`,
            `model_output`, `tool_result`, or `context_checkpoint` as the
            SSE event name and set the SSE `id` field to the event's
            `sequence`, which reconnects can replay via `Last-Event-ID`.
            Best-effort tool lifecycle updates use `tool_call_update`, model
            previews use `model_output_delta`, and stream-closing errors use
            `error`; none carries an SSE `id`, so reconnects resume from the
            last durable event. The response closes after every `error` frame.
            Raw clients reconnect when the error's stable code is
            `service_unavailable` and treat other current codes as terminal.
            Heartbeats are SSE comments and carry no JSON payload.
          content:
            text/event-stream:
              schema:
                $ref: '#/components/schemas/AgentEventStreamData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/cancel:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    post:
      operationId: cancelAgent
      tags: [Agents]
      summary: Cancel agent
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelAgentRequest'
      responses:
        '200':
          description: Agent canceled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelAgentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/interactions:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: listAgentInteractions
      tags: [Interactions]
      summary: List agent interactions
      description: Items are ordered by created_at ascending, then id ascending.
      parameters:
        - name: state
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/AgentInteractionState'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Agent interactions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentInteractionsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/interactions/{interactionID}/resolve:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: interactionID
        in: path
        required: true
        schema:
          type: string
          pattern: '^int_[a-z2-7]{26}$'
    post:
      operationId: resolveAgentInteraction
      tags: [Interactions]
      summary: Resolve agent interaction
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveAgentInteractionRequest'
      responses:
        '200':
          description: Agent interaction resolved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentInteraction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs/backlog:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
    get:
      operationId: listQueuedBacklogInputs
      tags: [Agents]
      summary: List waiting backlog inputs
      description: Steering inputs are listed first, followed by queued inputs. Each group is ordered by input rank, queued_at ascending, then id ascending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Waiting backlog inputs.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentInputsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs/{inputID}/cancel:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: inputID
        in: path
        required: true
        schema:
          type: string
          pattern: '^ain_[a-z2-7]{26}$'
    post:
      operationId: cancelQueuedBacklogInput
      tags: [Agents]
      summary: Cancel queued backlog input
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: Queued backlog input canceled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OKResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs/{inputID}/move:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: inputID
        in: path
        required: true
        schema:
          type: string
          pattern: '^ain_[a-z2-7]{26}$'
    post:
      operationId: moveQueuedBacklogInput
      tags: [Agents]
      summary: Move queued backlog input
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MoveQueuedBacklogInputRequest'
      responses:
        '200':
          description: Queued backlog input moved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OKResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs/{inputID}/promote_to_steering:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: inputID
        in: path
        required: true
        schema:
          type: string
          pattern: '^ain_[a-z2-7]{26}$'
    post:
      operationId: promoteQueuedInputToSteering
      tags: [Agents]
      summary: Promote queued input to steering
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromoteQueuedInputToSteeringRequest'
      responses:
        '200':
          description: Queued input promoted to steering.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OKResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/inputs/{inputID}/demote_to_queued:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: inputID
        in: path
        required: true
        schema:
          type: string
          pattern: '^ain_[a-z2-7]{26}$'
    post:
      operationId: demoteSteeringInputToQueued
      tags: [Agents]
      summary: Demote steering input to queued
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: Steering input demoted to queued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OKResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/artifacts/{artifactID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: artifactID
        in: path
        required: true
        schema:
          type: string
          pattern: '^art_[a-z2-7]{26}$'
    get:
      operationId: getArtifact
      tags: [Events]
      summary: Get artifact
      responses:
        '200':
          description: Artifact metadata.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Artifact'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/agents/{agentID}/artifacts/{artifactID}/content:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: agentID
        in: path
        required: true
        schema:
          type: string
          pattern: '^agt_[a-z2-7]{26}$'
      - name: artifactID
        in: path
        required: true
        schema:
          type: string
          pattern: '^art_[a-z2-7]{26}$'
    get:
      operationId: getArtifactContent
      tags: [Events]
      summary: Get artifact content
      responses:
        '200':
          description: Artifact bytes, served with the artifact's stored content type.
          content:
            '*/*':
              schema:
                type: string
                format: binary
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/machines:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    get:
      operationId: listVisibleProjectMachines
      tags: [Machines]
      summary: List visible project machines
      description: Items are ordered by machine created_at descending, then machine id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/MachineSourceKindFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Machines visible in the project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListVisibleMachinesResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/machine-grants:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createProjectMachineGrant
      tags: [Machines]
      summary: Create project machine grant
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProjectMachineGrantRequest'
      responses:
        '200':
          description: Existing project machine grant returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateProjectMachineGrantResponse'
        '201':
          description: Project machine grant created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateProjectMachineGrantResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listProjectMachineGrants
      tags: [Machines]
      summary: List project machine grants
      description: Lists explicit machine grants that can be deleted directly. Pool-derived machine access is managed through project machine pool grants.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Project machine grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectMachineGrantsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/machine-grants/{grantID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: grantID
        in: path
        required: true
        schema:
          type: string
          pattern: '^pmg_[a-z2-7]{26}$'
    delete:
      operationId: deleteProjectMachineGrant
      tags: [Machines]
      summary: Delete project machine grant
      description: >-
        Removes the project's access to the machine. Processes that depended on the grant are stopped.
        The machine itself is retained, and there are no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project machine grant deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/secrets:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    get:
      operationId: listProjectAvailableSecrets
      tags: [Secrets]
      summary: List secrets available to project
      description: Includes directly owned and granted secrets, ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/SecretKindFilter'
        - $ref: '#/components/parameters/SecretOwnerKindFilter'
        - $ref: '#/components/parameters/SecretAvailabilitySourceFilter'
        - $ref: '#/components/parameters/SecretMetadataFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Secrets available to the project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectSecretAccessesResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/secrets/{secretID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: secretID
        in: path
        required: true
        schema:
          type: string
          pattern: '^sec_[a-z2-7]{26}$'
    get:
      operationId: getProjectAvailableSecret
      tags: [Secrets]
      summary: Get secret available to project
      responses:
        '200':
          description: Secret available to the project and its availability source.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectSecretAccess'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/actors:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    get:
      operationId: listActors
      tags: [Actors]
      summary: List project actors
      description: Items are ordered by created_at ascending, then id ascending.
      parameters:
        - name: provider
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/ActorProvider'
        - name: provider_tenant_id
          in: query
          required: false
          schema:
            type: string
        - name: provider_user_id
          in: query
          required: false
          schema:
            type: string
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Project actors.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListActorsResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    put:
      operationId: putActor
      tags: [Actors]
      summary: Upsert an external actor
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      description: Upserts by (provider_tenant_id, provider_user_id). Omitted attributes keep their stored values; provided attributes are overwritten, including empty values. An unchanged actor is not rewritten. Actors written through this endpoint always have the external provider.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalActorParams'
      responses:
        '200':
          description: The upserted actor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Actor'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/actors/{actorID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: actorID
        in: path
        required: true
        schema:
          type: string
          pattern: '^actr_[a-z2-7]{26}$'
    get:
      operationId: getActor
      tags: [Actors]
      summary: Get a project actor
      responses:
        '200':
          description: The actor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Actor'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/InternalServerError' }
        '503': { $ref: '#/components/responses/ServiceUnavailable' }
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machines:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: createMachine
      tags: [Machines]
      summary: Create machine
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMachineRequest'
      responses:
        '200':
          description: Existing machine returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Machine'
        '201':
          description: Machine created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Machine'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listVisibleMachines
      tags: [Machines]
      summary: List visible machines
      description: Items are ordered by machine created_at descending, then machine id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - $ref: '#/components/parameters/MachineSourceKindFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Machines visible to the authenticated user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListVisibleMachinesResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machines/connect:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/OrganizationID'
    post:
      operationId: connectBYOMachine
      tags: [Machines]
      summary: Connect a BYO machine
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConnectBYOMachineRequest'
      responses:
        '201':
          description: Machine, daemon token, and selected project grants created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConnectBYOMachineResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machines/{machineID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: machineID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mch_[a-z2-7]{26}$'
    get:
      operationId: getMachine
      tags: [Machines]
      summary: Get machine
      responses:
        '200':
          description: Machine.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Machine'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateMachine
      tags: [Machines]
      summary: Update machine execution defaults
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMachineRequest'
      responses:
        '200':
          description: Machine updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Machine'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteMachine
      tags: [Machines]
      summary: Delete machine
      description: >-
        Deletes a BYO machine, ends its active daemon runtimes and work, revokes its daemon tokens
        and project grants, and releases agent bindings. Pooled machines are managed through their
        machine pool and cannot be deleted through this route. There are no dependency blockers for
        a BYO machine.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/model-provider-configs:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: createModelProviderConfig
      tags: [Models]
      summary: Create model provider config
      description: Create a model provider config, validate the configured credential where the provider exposes a validation endpoint, then probe the provider's /models endpoint. The result is returned as model_catalog; a failed probe does not fail creation.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateModelProviderConfigRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateModelProviderConfigResponse'
        '201':
          description: Created route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateModelProviderConfigResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listModelProviderConfigs
      tags: [Models]
      summary: List model provider configs
      description: List model provider configs with server-side filtering, sorting, and cursor pagination.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelProviderConfigList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/model-provider-configs/{modelProviderConfigID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: modelProviderConfigID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mpc_[a-z2-7]{26}$'
    get:
      operationId: getModelProviderConfig
      tags: [Models]
      summary: Get model provider config
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelProviderConfig'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    put:
      operationId: updateModelProviderConfig
      tags: [Models]
      summary: Update model provider config
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateModelProviderConfigRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelProviderConfig'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteModelProviderConfig
      tags: [Models]
      summary: Delete model provider config
      description: >-
        Deletes only the model provider config. Deletion is blocked while it has configured models.
        Cluster-managed provider configs cannot be deleted through this route.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/model-provider-configs/{modelProviderConfigID}/model-catalog:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/OrganizationID'
      - name: modelProviderConfigID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ModelProviderConfigID'
    get:
      operationId: getModelCatalog
      tags: [Models]
      summary: Get model catalog
      description: >-
        Fetches the provider's live model catalog by validating the configured credential and
        probing the provider's /models endpoint. The call waits on the upstream provider, so it
        is slower than the other model provider config routes and can report failure as data.
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelCatalog'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/model-provider-configs/{modelProviderConfigID}/models:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: modelProviderConfigID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mpc_[a-z2-7]{26}$'
    post:
      operationId: createConfiguredModel
      tags: [Models]
      summary: Create configured model
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateConfiguredModelRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfiguredModel'
        '201':
          description: Created route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfiguredModel'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listConfiguredModels
      tags: [Models]
      summary: List configured models
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfiguredModelList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/model-provider-configs/{modelProviderConfigID}/models/{configuredModelID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: modelProviderConfigID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mpc_[a-z2-7]{26}$'
      - name: configuredModelID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mdl_[a-z2-7]{26}$'
    put:
      operationId: updateConfiguredModel
      tags: [Models]
      summary: Update configured model
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateConfiguredModelRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfiguredModel'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteConfiguredModel
      tags: [Models]
      summary: Delete configured model
      description: >-
        Deletes only the configured model. Deletion is blocked while it has active project grants.
        Cluster-managed configured models cannot be deleted through this route.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/model-grants:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createProjectModelGrant
      tags: [Models]
      summary: Create project model grant
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProjectModelGrantRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectModelGrantEnvelope'
        '201':
          description: Created route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectModelGrantEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listProjectModelGrants
      tags: [Models]
      summary: List project model grants
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectModelGrantsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/model-grants/{modelGrantID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: modelGrantID
        in: path
        required: true
        schema:
          type: string
          pattern: '^pmog_[a-z2-7]{26}$'
    delete:
      operationId: deleteProjectModelGrant
      tags: [Models]
      summary: Delete project model grant
      description: >-
        Removes the project's access to the configured model. The grant is live policy: new launches
        can no longer select the model, and agents already using it lose access on their next model
        call. The model itself is retained, and there are no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project model grant deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateProjectModelGrant
      tags: [Models]
      summary: Update project model grant
      description: >-
        Updates the project's overrides for the configured model. Omitted fields keep their current
        values; null clears an override so the project inherits from the configured model. The grant
        is live policy: agents already using the model re-apply the updated overrides on their next
        model call, against the configured-model revision each agent pinned at launch. Updates are
        validated against the configured model's current revision only, so an update can make an
        agent pinned to an older, incompatible revision fail its next model call.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProjectModelGrantRequest'
      responses:
        '200':
          description: Route response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectModelGrantEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machine-pools:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
    post:
      operationId: createMachinePool
      tags: [Machine Pools]
      summary: Create machine pool
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMachinePoolRequest'
      responses:
        '200':
          description: Existing machine pool returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MachinePool'
        '201':
          description: Machine pool created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MachinePool'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listMachinePools
      tags: [Machine Pools]
      summary: List machine pools
      description: List machine pools with server-side filtering, sorting, and cursor pagination.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Machine pools.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListMachinePoolsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machine-pools/{poolID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: poolID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mpo_[a-z2-7]{26}$'
    get:
      operationId: getMachinePool
      tags: [Machine Pools]
      summary: Get machine pool
      responses:
        '200':
          description: Machine pool.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MachinePool'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    put:
      operationId: updateMachinePool
      tags: [Machine Pools]
      summary: Update machine pool
      description: >-
        Tenant-managed pools support every request field. Cluster-managed pools only allow changes to
        default CPU and memory, environment and secret environment variables, provider-supported
        per-machine CPU and memory limits, and the idle deletion policy. Other cluster-managed changes
        are rejected with 409 Conflict.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMachinePoolRequest'
      responses:
        '200':
          description: Machine pool updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MachinePool'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    delete:
      operationId: deleteMachinePool
      tags: [Machine Pools]
      summary: Delete machine pool
      description: >-
        Deletes the machine pool and its pooled machines, revokes generated machine grants and project
        machine-pool grants, and stops processes that depended on those grants. Deleting a
        cluster-managed machine pool is rejected with 409 Conflict; there are no other dependency
        blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Resource deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/machine-pool-grants:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
    post:
      operationId: createProjectMachinePoolGrant
      tags: [Machine Pools]
      summary: Create project machine pool grant
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProjectMachinePoolGrantRequest'
      responses:
        '200':
          description: Existing project machine pool grant returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMachinePoolGrant'
        '201':
          description: Project machine pool grant created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMachinePoolGrant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listProjectMachinePoolGrants
      tags: [Machine Pools]
      summary: List project machine pool grants
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/ResourceNameFilter'
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ResourceListSort'
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Project machine pool grants.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectMachinePoolGrantsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/projects/{projectID}/machine-pool-grants/{poolGrantID}:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          pattern: '^proj_[a-z2-7]{26}$'
      - name: poolGrantID
        in: path
        required: true
        schema:
          type: string
          pattern: '^pmpg_[a-z2-7]{26}$'
    delete:
      operationId: deleteProjectMachinePoolGrant
      tags: [Machine Pools]
      summary: Delete project machine pool grant
      description: >-
        Removes the project's access to the machine pool, revokes machine grants generated through it,
        and stops processes that depended on those grants. The pool itself is retained, and there are
        no dependency blockers.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '204':
          description: Project machine pool grant deleted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: getProjectMachinePoolGrant
      tags: [Machine Pools]
      summary: Get project machine pool grant
      responses:
        '200':
          description: Project machine pool grant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMachinePoolGrant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    patch:
      operationId: updateProjectMachinePoolGrant
      tags: [Machine Pools]
      summary: Update project machine pool grant
      description: >-
        Updates the grant's overrides and limits. Omitted fields keep their current values; null
        clears an override so the grant follows the machine pool again. Overlay objects and metadata
        are replaced whole when present. Existing machines keep their configuration; the updated
        defaults and limits apply to new launches.
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProjectMachinePoolGrantRequest'
      responses:
        '200':
          description: Project machine pool grant updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectMachinePoolGrant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machines/{machineID}/daemon-tokens:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: machineID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mch_[a-z2-7]{26}$'
    post:
      operationId: createBYOMachineDaemonToken
      tags: [Machines]
      summary: Create byo machine daemon token
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMachineDaemonTokenRequest'
      responses:
        '201':
          description: Machine daemon token created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateMachineDaemonTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
    get:
      operationId: listBYOMachineDaemonTokens
      tags: [Machines]
      summary: List byo machine daemon tokens
      description: Items are ordered by created_at descending, then id descending.
      parameters:
        - $ref: '#/components/parameters/PageLimit'
        - $ref: '#/components/parameters/PageCursor'
      responses:
        '200':
          description: Machine daemon tokens.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListMachineDaemonTokensResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /orgs/{orgID}/machines/{machineID}/daemon-tokens/{tokenID}/revoke:
    parameters:
      - name: orgID
        in: path
        required: true
        schema:
          type: string
          pattern: '^org_[a-z2-7]{26}$'
      - name: machineID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mch_[a-z2-7]{26}$'
      - name: tokenID
        in: path
        required: true
        schema:
          type: string
          pattern: '^mdt_[a-z2-7]{26}$'
    post:
      operationId: revokeMachineDaemonToken
      tags: [Machines]
      summary: Revoke machine daemon token
      security:
        - bearerAuth: []
        - browserSessionCookie: []
          csrfHeader: []
      responses:
        '200':
          description: Machine daemon token revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MachineDaemonToken'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/runtimes:
    post:
      operationId: registerMachineDaemonRuntime
      x-hidden: true
      security:
        - machineDaemonAuth: []
      tags: [Machine Daemon]
      summary: Register machine daemon runtime
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterDaemonRuntimeRequest'
      responses:
        '201':
          description: Machine daemon runtime registered.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegisterDaemonRuntimeResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '410':
          $ref: '#/components/responses/Gone'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/runtimes/{runtimeID}/socket:
    parameters:
      - name: runtimeID
        in: path
        required: true
        schema:
          type: string
          pattern: '^drt_[a-z2-7]{26}$'
    get:
      operationId: socketMachineDaemonRuntime
      x-hidden: true
      security:
        - machineDaemonAuth: []
      tags: [Machine Daemon]
      summary: Socket machine daemon runtime
      responses:
        '101':
          description: WebSocket upgrade accepted.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '410':
          $ref: '#/components/responses/Gone'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/runtimes/{runtimeID}/end:
    parameters:
      - name: runtimeID
        in: path
        required: true
        schema:
          type: string
          pattern: '^drt_[a-z2-7]{26}$'
    post:
      operationId: endMachineDaemonRuntime
      x-hidden: true
      security:
        - machineDaemonAuth: []
      tags: [Machine Daemon]
      summary: End machine daemon runtime
      responses:
        '200':
          description: Machine daemon runtime ended.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DaemonRuntime'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '410':
          $ref: '#/components/responses/Gone'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/runtimes/{runtimeID}/sleep:
    parameters:
      - name: runtimeID
        in: path
        required: true
        schema:
          type: string
          pattern: '^drt_[a-z2-7]{26}$'
    post:
      operationId: sleepMachineDaemonRuntime
      x-hidden: true
      security:
        - machineDaemonAuth: []
      tags: [Machine Daemon]
      summary: Sleep machine daemon runtime
      description: >-
        Gracefully ends the daemon runtime and marks the machine asleep so new
        work queues and triggers an automatic wake. Rejected with 409 code
        pending_work when the machine has queued or live daemon work, and 409
        code not_wake_capable when the machine has no sandbox URL.
      responses:
        '200':
          description: Machine daemon runtime ended for sleep; machine marked asleep.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DaemonRuntime'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The machine cannot sleep right now.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '410':
          $ref: '#/components/responses/Gone'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/skills/{skillID}/archive:
    parameters:
      - name: skillID
        in: path
        required: true
        schema:
          type: string
          pattern: '^skl_[a-z2-7]{26}$'
    get:
      operationId: getDaemonSkillArchive
      x-hidden: true
      tags: [Machine Daemon]
      summary: Get daemon skill archive
      description: Requires daemon authentication plus a short-lived capability bound to the authenticated machine, skill, and revision.
      security:
        - machineDaemonAuth: []
      parameters:
        - name: revision_id
          in: query
          required: true
          schema:
            type: string
            pattern: '^skr_[a-z2-7]{26}$'
        - name: expires_at
          in: query
          required: true
          schema:
            type: integer
            format: int64
        - name: download_token
          in: query
          required: true
          schema:
            type: string
            minLength: 64
            maxLength: 64
      responses:
        '200':
          description: Skill archive bytes.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '410':
          $ref: '#/components/responses/Gone'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/tool-calls/{toolCallID}/artifact:
    parameters:
      - name: toolCallID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ToolCallID'
    post:
      operationId: uploadDaemonArtifact
      x-hidden: true
      tags: [Machine Daemon]
      summary: Upload daemon artifact
      security:
        - machineDaemonAuth: []
      parameters:
        - name: filename
          in: query
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 255
      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
      responses:
        '201':
          description: Artifact created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadArtifactResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '413':
          description: The uploaded artifact is too large.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
  /daemon/tool-calls/{toolCallID}/artifacts/{artifactID}/content:
    parameters:
      - name: toolCallID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ToolCallID'
      - name: artifactID
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ArtifactID'
    get:
      operationId: downloadDaemonArtifact
      x-hidden: true
      tags: [Machine Daemon]
      summary: Download daemon artifact
      security:
        - machineDaemonAuth: []
      responses:
        '200':
          description: Artifact bytes, served with the artifact's stored content type.
          content:
            '*/*':
              schema:
                type: string
                format: binary
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '4XX':
          $ref: '#/components/responses/ClientError'
        '5XX':
          $ref: '#/components/responses/ServerError'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Omnara personal or organization access token
      description: An opaque Omnara personal or organization bearer token.
    browserSessionCookie:
      type: apiKey
      in: cookie
      name: __Host-omnara_session
      description: Browser session cookie. HTTPS deployments use __Host-omnara_session; local HTTP development uses omnara_session.
    csrfHeader:
      type: apiKey
      in: header
      name: X-Omnara-Csrf
      description: CSRF token header required for browser-session mutations. The value must match the session's CSRF cookie.
    machineDaemonAuth:
      type: http
      scheme: bearer
      bearerFormat: Omnara machine daemon token
      description: An opaque Omnara machine-daemon bearer token. The bootstrap route derives the organization, installation, and machine identity from the credential; runtime routes verify that the addressed runtime belongs to the token-derived machine.
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        minLength: 1
        maxLength: 255
      description: Idempotency key for replay-safe mutating requests.
    PageLimit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 100
        default: 50
      description: Maximum number of items to return in one page.
    PageCursor:
      name: cursor
      in: query
      required: false
      schema:
        type: string
        maxLength: 1024
      description: Opaque pagination cursor from a previous response's next_cursor. Omit for the first page.
    ResourceNameFilter:
      name: name
      in: query
      required: false
      schema:
        type: string
        minLength: 1
        maxLength: 200
      description: Case-insensitive glob over the list's logical name. `*` matches zero or more characters, `?` matches one character, and `\` escapes a wildcard.
    MachineSourceKindFilter:
      name: source_kind
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/MachineSourceKind'
      description: Filter machines by source kind. Omit to include both BYO and pooled machines.
    SecretMetadataFilter:
      name: metadata
      in: query
      required: false
      style: deepObject
      explode: true
      description: Metadata key/value filters, encoded as metadata[key]=value.
      schema:
        type: object
        additionalProperties:
          type: string
    SecretKindFilter:
      name: kind
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/SecretKind'
      description: Filter secrets by material kind.
    SkillOwnerKindFilter:
      name: owner_kind
      in: query
      required: false
      schema:
        type: string
        enum: [org, project, user]
      description: Filter by the immutable skill owner kind.
    SkillOwnerProjectIDFilter:
      name: owner_project_id
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/ProjectID'
      description: Required with owner_kind=project and invalid with other owner kinds.
    SkillAvailabilitySourceFilter:
      name: availability_source
      in: query
      required: false
      schema:
        type: string
        enum: [direct, grant]
      description: Filter a project inventory by how the skill became available.
    SecretOwnerKindFilter:
      name: owner_kind
      in: query
      required: false
      schema:
        type: string
        enum: [org, project, user]
      description: Filter by the immutable owner kind.
    SecretOwnerProjectIDFilter:
      name: owner_project_id
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/ProjectID'
      description: Required with owner_kind=project and invalid with other owner kinds.
    SecretMCPOAuthFlowIDFilter:
      name: mcp_oauth_flow_id
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/MCPOAuthFlowID'
      description: Filter to secrets that have a version created by this MCP OAuth flow.
    IntegrationInstallAgentProfileFilter:
      name: agent_profile_id
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/AgentProfileID'
      description: Only return integration installs bound to this agent profile.
    IntegrationInstallOAuthFlowIDFilter:
      name: oauth_flow_id
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/IntegrationOAuthFlowID'
      description: Only return the integration install completed by this OAuth setup flow.
    SecretAvailabilitySourceFilter:
      name: availability_source
      in: query
      required: false
      schema:
        type: string
        enum: [direct, grant]
      description: Filter a project inventory by how the secret became available.
  responses:
    BadRequest:
      description: The request was invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Authentication is required or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: The authenticated principal is not authorized.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The requested resource was not found or is not visible.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: The request conflicts with current resource state or idempotency history.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Gone:
      description: The requested resource is no longer available.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: The request cannot be processed in its current form.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadGateway:
      description: An upstream service required to satisfy the request failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: An unexpected internal server error occurred.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: The service dependency required to satisfy the request is unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ClientError:
      description: Any other client error. The body carries the shared Error envelope restricted to client error codes; statuses with a dedicated response above are documented precisely.
      content:
        application/json:
          schema:
            type: object
            additionalProperties: false
            required: [error, code]
            properties:
              error:
                type: string
                description: Human-readable error message. Do not match on it programmatically.
              code:
                $ref: '#/components/schemas/ClientErrorCode'
    ServerError:
      description: Any other server error. The body carries the shared Error envelope restricted to server error codes.
      content:
        application/json:
          schema:
            type: object
            additionalProperties: false
            required: [error, code]
            properties:
              error:
                type: string
                description: Human-readable error message. Do not match on it programmatically.
              code:
                $ref: '#/components/schemas/ServerErrorCode'
  schemas:
    ResourceName:
      type: string
      minLength: 1
      maxLength: 64
      x-omnara-unicode-normalization: NFC
      description: Human-readable name. Spaces and punctuation are allowed; leading or trailing whitespace and invisible or control characters are not.
    AgentName:
      type: string
      maxLength: 64
      x-omnara-unicode-normalization: NFC
      description: Agent name. Empty means the agent is unnamed; non-empty values use the ResourceName policy.
    SkillName:
      type: string
      minLength: 1
      maxLength: 64
      pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'
      description: Machine-readable skill identifier consisting of lowercase ASCII segments separated by single hyphens.
    ResourceListSort:
      type: string
      description: Sort order for named resources that expose created and modified timestamps.
      default: -created_at
      enum: [name, -name, -updated_at, updated_at, -created_at, created_at]
    CreatedResourceListSort:
      type: string
      description: Sort order for named resources that expose a created timestamp.
      default: -created_at
      enum: [name, -name, -created_at, created_at]
    AgentConfigErrorIssue:
      type: object
      additionalProperties: false
      required: [path, message]
      properties:
        path:
          type: string
          description: >-
            JSON Pointer (RFC 6901) to the offending field in the submitted document.
            An empty string refers to the whole document.
        message:
          type: string
          description: Human-readable description of the problem with this field.
        line:
          type: integer
          minimum: 1
          description: 1-based line of the offending field in the submitted source, when it can be located.
        column:
          type: integer
          minimum: 1
          description: 1-based column of the offending field in the submitted source, when it can be located.
    Error:
      type: object
      additionalProperties: false
      required: [error, code]
      properties:
        error:
          type: string
          description: Human-readable error message. Do not match on it programmatically.
        issues:
          type: array
          description: >-
            Field-level problems when a submitted document (such as an agent config source)
            failed validation. Absent for errors that are not about a specific field.
          items:
            $ref: '#/components/schemas/AgentConfigErrorIssue'
        code:
          type: string
          description: Stable error code for programmatic handling.
          enum:
            - invalid_request
            - unauthorized
            - forbidden
            - not_found
            - conflict
            - gone
            - request_too_large
            - unsupported_media_type
            - unprocessable
            - rate_limited
            - internal_error
            - upstream_error
            - service_unavailable
            - idempotency_key_conflict
            - state_transition_conflict
            - managed_work_admission_denied
            - pending_work
            - not_wake_capable
            - daemon_runtime_unregistered
            - validation_failed
            - csrf_check_failed
            - authentication_unavailable
    Warning:
      type: object
      additionalProperties: false
      required: [message, code]
      properties:
        message:
          type: string
          description: Human-readable warning message. Do not match on it programmatically.
        code:
          type: string
          description: Stable warning code for programmatic handling.
          enum:
            - missing_recommended_machine_tools
    ClientErrorCode:
      type: string
      description: Stable error code carried by 4XX statuses. Subset of the Error code enum whose statuses are client errors.
      enum:
        - invalid_request
        - validation_failed
        - unauthorized
        - forbidden
        - csrf_check_failed
        - not_found
        - conflict
        - idempotency_key_conflict
        - state_transition_conflict
        - pending_work
        - not_wake_capable
        - gone
        - daemon_runtime_unregistered
        - request_too_large
        - unsupported_media_type
        - unprocessable
        - rate_limited
    ServerErrorCode:
      type: string
      description: Stable error code carried by 5XX statuses. Subset of the Error code enum whose statuses are server errors.
      enum:
        - internal_error
        - upstream_error
        - service_unavailable
        - authentication_unavailable
    ManagementKind:
      type: string
      description: >-
        Lifecycle owner. Tenant-managed resources can be changed through tenant APIs. Cluster-managed
        resources are installed and lifecycle-managed by the control plane; individual APIs may explicitly
        expose tenant-editable settings.
      enum: [tenant, cluster]
    OrganizationID:
      type: string
      pattern: '^org_[a-z2-7]{26}$'
    OrgInvitationID:
      type: string
      pattern: '^oinv_[a-z2-7]{26}$'
    PersonalAccessTokenID:
      type: string
      pattern: '^pat_[a-z2-7]{26}$'
    OrgAPIKeyID:
      type: string
      pattern: '^oak_[a-z2-7]{26}$'
    ProjectID:
      type: string
      pattern: '^proj_[a-z2-7]{26}$'
    MCPOAuthFlowID:
      type: string
      pattern: '^moaf_[a-z2-7]{26}$'
    IntegrationOAuthFlowID:
      type: string
      pattern: '^ioaf_[a-z2-7]{26}$'
    ActorID:
      type: string
      pattern: '^actr_[a-z2-7]{26}$'
    AgentID:
      type: string
      pattern: '^agt_[a-z2-7]{26}$'
    AgentConfigID:
      type: string
      pattern: '^acfg_[a-z2-7]{26}$'
    AgentProfileID:
      type: string
      pattern: '^aprf_[a-z2-7]{26}$'
    CronTriggerID:
      type: string
      pattern: '^cron_[a-z2-7]{26}$'
    IntegrationInstallID:
      type: string
      pattern: '^iin_[a-z2-7]{26}$'
    AgentEventID:
      type: string
      pattern: '^evt_[a-z2-7]{26}$'
    ModelCallContextID:
      type: string
      pattern: '^mcc_[a-z2-7]{26}$'
    AgentInputID:
      type: string
      pattern: '^ain_[a-z2-7]{26}$'
    AgentMachineBindingID:
      type: string
      pattern: '^amb_[a-z2-7]{26}$'
    AgentTurnID:
      type: string
      pattern: '^trn_[a-z2-7]{26}$'
    AgentInteractionID:
      type: string
      pattern: '^int_[a-z2-7]{26}$'
    ToolCallID:
      type: string
      pattern: '^tcl_[a-z2-7]{26}$'
    ContextCheckpointID:
      type: string
      pattern: '^ccp_[a-z2-7]{26}$'
    ArtifactID:
      type: string
      pattern: '^art_[a-z2-7]{26}$'
    ModelProviderConfigID:
      type: string
      pattern: '^mpc_[a-z2-7]{26}$'
    ConfiguredModelID:
      type: string
      pattern: '^mdl_[a-z2-7]{26}$'
    ConfiguredModelRevisionID:
      type: string
      pattern: '^mrev_[a-z2-7]{26}$'
    ProjectModelGrantID:
      type: string
      pattern: '^pmog_[a-z2-7]{26}$'
    ModelAPIFormat:
      type: string
      enum: [openai-responses, openai-chat-completions, anthropic-messages]
      x-enum-varnames:
        - ModelAPIFormatOpenaiResponses
        - ModelAPIFormatOpenaiChatCompletions
        - ModelAPIFormatAnthropicMessages
    ModelProviderAuthKind:
      type: string
      enum: [bearer_token, api_key_header]
    ModelProviderAPIVariant:
      type: string
      enum: [default, openrouter, bedrock]
    ModelProviderAPIVariantResponse:
      type: string
      x-extensible-enum: [default, openrouter, bedrock]
    ModelAPIVariantOptions:
      type: object
      x-go-type: json.RawMessage
      x-go-type-skip-optional-pointer: true
      description: >-
        Extra top-level JSON fields to include in provider requests for this
        configured model. Use this for provider-specific settings that Omnara
        does not expose as typed fields, such as OpenRouter `provider` routing
        or sampling parameters. Omnara still controls the fields it needs to run
        the agent correctly, including the model, prompt/messages, streaming,
        tools, output-token limit, and selected reasoning policy. Provider
        passthrough values for those fields are ignored. For OpenRouter routing
        options, see
        https://openrouter.ai/docs/guides/routing/provider-selection and general
        request parameters at https://openrouter.ai/docs/api/reference/parameters.
        Omnara-managed OpenRouter providers accept only sampling, reasoning,
        and per-model routing options here.
      additionalProperties: true
    ModelCacheRetention:
      type: string
      description: >-
        Prompt-cache preference for model requests; `short` when omitted.
        `short` applies the route's default caching (explicit cache
        breakpoints where the provider requires them) and, where the route
        accepts one, a stable conversation key for cache-aware routing.
        `long` prefers the
        route's extended cache lifetime where one exists (currently Anthropic's
        one-hour cache, which on Bedrock requires Claude 4.5 or newer) and
        behaves like `short` elsewhere. `none`
        sends no Omnara-managed cache controls or conversation key; providers
        may still cache prefixes on their own.
      enum: [none, short, long]
    CreateModelProviderConfigRequest:
      type: object
      description: Connect Omnara to a model API endpoint. Use a preset for built-in providers, or provide api_format and base_url for a custom endpoint. When omitted, endpoint_path and auth settings are filled from api_format.
      additionalProperties: false
      required: [name, credential_secret_id]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        preset:
          type: string
          enum: [openai, openrouter, anthropic]
        api_format:
          $ref: '#/components/schemas/ModelAPIFormat'
        api_variant:
          $ref: '#/components/schemas/ModelProviderAPIVariant'
        base_url:
          type: string
          minLength: 1
          description: Provider endpoint base URL. Normal API mode requires a public HTTPS endpoint; localhost and loopback endpoints are accepted only when the API is running in insecure dev mode.
        endpoint_path:
          type: string
          minLength: 1
          pattern: '^/'
          description: URL path under base_url. Defaults to /responses for OpenAI Responses, /chat/completions for Chat Completions, and /messages for Anthropic Messages.
        request_timeout_ms:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Provider request timeout in milliseconds. Omitted value defaults to 600000.
        auth_kind:
          $ref: '#/components/schemas/ModelProviderAuthKind'
        auth_options:
          type: object
          x-go-type: json.RawMessage
          x-go-type-skip-optional-pointer: true
          description: Non-secret API-key placement settings. Use an empty object with bearer_token. With api_key_header, set {"header_name":"..."}; Anthropic Messages defaults to {"header_name":"x-api-key"}.
          additionalProperties: false
          properties:
            header_name:
              type: string
              minLength: 1
        credential_secret_id:
          $ref: '#/components/schemas/SecretID'
    UpdateModelProviderConfigRequest:
      type: object
      description: Update a provider config. Omitted fields keep their current values.
      additionalProperties: false
      properties:
        base_url:
          type: string
          minLength: 1
          description: Provider endpoint base URL. Normal API mode requires a public HTTPS endpoint; localhost and loopback endpoints are accepted only when the API is running in insecure dev mode.
        endpoint_path:
          type: string
          minLength: 1
          pattern: '^/'
          description: URL path under base_url. This changes where requests are sent, not which API format Omnara speaks.
        request_timeout_ms:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Provider request timeout in milliseconds.
        auth_kind:
          $ref: '#/components/schemas/ModelProviderAuthKind'
        auth_options:
          type: object
          x-go-type: json.RawMessage
          x-go-type-skip-optional-pointer: true
          description: Non-secret API-key placement settings. Use an empty object with bearer_token. With api_key_header, set {"header_name":"..."}.
          additionalProperties: false
          properties:
            header_name:
              type: string
              minLength: 1
        credential_secret_id:
          $ref: '#/components/schemas/SecretID'
    ModelProviderConfig:
      type: object
      additionalProperties: false
      required: [id, org_id, management_kind, name, api_format, api_variant, base_url, endpoint_path, request_timeout_ms, auth_kind, auth_options, credential_secret_id, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ModelProviderConfigID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        management_kind:
          $ref: '#/components/schemas/ManagementKind'
        name:
          $ref: '#/components/schemas/ResourceName'
        api_format:
          $ref: '#/components/schemas/ModelAPIFormat'
        api_variant:
          $ref: '#/components/schemas/ModelProviderAPIVariantResponse'
        base_url:
          type: string
          description: Provider endpoint base URL. Normal API mode uses public HTTPS endpoints; localhost and loopback endpoints are only for insecure dev-mode configs.
        endpoint_path:
          type: string
        request_timeout_ms:
          type: integer
        auth_kind:
          $ref: '#/components/schemas/ModelProviderAuthKind'
        auth_options:
          type: object
          x-go-type: json.RawMessage
          x-go-type-skip-optional-pointer: true
          description: Non-secret API-key placement settings for this provider config.
          additionalProperties: false
          properties:
            header_name:
              type: string
              minLength: 1
        credential_secret_id:
          $ref: '#/components/schemas/SecretID'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CreateModelProviderConfigResponse:
      type: object
      additionalProperties: false
      required: [config, model_catalog]
      properties:
        config:
          $ref: '#/components/schemas/ModelProviderConfig'
        model_catalog:
          $ref: '#/components/schemas/ModelCatalog'
    ModelCatalog:
      type: object
      description: The provider's model catalog, obtained by validating the configured credential and probing the provider's /models endpoint. A failed probe does not affect the stored config; treat it as a warning that the base URL or API key may be invalid.
      additionalProperties: false
      required: [status]
      properties:
        status:
          type: string
          enum: [ok, failed]
        models:
          type: array
          description: Models advertised by the provider, newest first, filtered to text-output tool-calling models where the provider exposes enough metadata to tell. Present when status is ok.
          items:
            $ref: '#/components/schemas/DiscoveredProviderModel'
        error:
          type: string
          description: Why the probe failed. Present when status is failed.
    DiscoveredProviderModel:
      type: object
      additionalProperties: false
      required: [slug]
      properties:
        slug:
          type: string
          description: Provider model slug usable as a configured model's provider_model_slug.
        display_name:
          type: string
        context_window_tokens:
          type: integer
          minimum: 2
          maximum: 2147483647
          description: Provider-advertised context window limit in tokens, when available.
        max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Provider-advertised maximum output limit in tokens, when available.
    ModelProviderConfigList:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ModelProviderConfig'
        next_cursor:
          type: [string, "null"]
    CreateConfiguredModelRequest:
      type: object
      additionalProperties: false
      required: [name, provider_model_slug, context_window_tokens]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
          description: User-assigned configured model name used by agent YAML as model.name. Names are unique within an active model provider config and can be renamed without changing existing agents.
        provider_model_slug:
          type: string
          minLength: 1
          description: >-
            Exact provider model slug sent to the provider endpoint. Free-pool,
            `:online`, and preset model ids are not accepted on Omnara-managed
            OpenRouter providers.
        context_window_tokens:
          type: integer
          minimum: 2
          maximum: 2147483647
          description: Total token window for this model, including input and output.
        max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Optional configured output-token ceiling. When omitted, Omnara stores the smaller of 8,192 tokens and half the context window. It must not exceed the provider's supported limit. Omnara uses it for request validation and context budgeting.
        default_max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Optional normal per-request output-token cap. When omitted, Omnara stores the smaller of 4,096 tokens and max_output_tokens.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: boolean
          description: Whether this configured model can receive tool definitions and emit tool calls. Agent configs with enabled tools are rejected when this is false.
          default: true
        supports_reasoning:
          type: boolean
          description: Whether Omnara should use this model's reasoning features. For OpenAI Responses, this also enables encrypted reasoning replay for stateless calls.
          default: false
        default_reasoning_effort:
          type: string
          description: Default reasoning effort to send for models/API formats that support effort-style reasoning controls. Requires supports_reasoning=true. When supported_reasoning_efforts is present, this value must be listed there.
        supported_reasoning_efforts:
          type: array
          description: Reasoning effort values this configured model accepts. Requires supports_reasoning=true when non-empty.
          items:
            type: string
        input_modalities:
          type: array
          description: Input types this configured model accepts. Omnara recognizes text, image, and file; an empty list leaves capabilities unspecified.
          items:
            type: string
        output_modalities:
          type: array
          description: Output types this configured model can return. Omnara currently consumes text output.
          items:
            type: string
        api_variant_options:
          $ref: '#/components/schemas/ModelAPIVariantOptions'
    UpdateConfiguredModelRequest:
      type: object
      description: Update a configured model. Omitted fields keep their current values. Runtime changes create a new immutable model revision; changing only name just renames the model.
      additionalProperties: false
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
          description: User-assigned configured model name used by agent YAML as model.name. Renaming affects future YAML resolution but does not change existing agents.
        provider_model_slug:
          type: string
          minLength: 1
          description: >-
            Exact provider model slug sent to the provider endpoint. Free-pool,
            `:online`, and preset model ids are not accepted on Omnara-managed
            OpenRouter providers.
        context_window_tokens:
          type: integer
          minimum: 2
          maximum: 2147483647
          description: Total token window for this model, including input and output.
        max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Configured output-token ceiling for this model. Omitted keeps the current value; it cannot be cleared.
        default_max_output_tokens:
          type: [integer, "null"]
          minimum: 1
          maximum: 2147483647
          description: Default per-request output-token cap sent to the provider unless an agent config overrides it. Required for Anthropic Messages.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: boolean
          description: Whether this configured model can receive tool definitions and emit tool calls. Agent configs with enabled tools are rejected when this is false. Omitted keeps the current value.
        supports_reasoning:
          type: boolean
          description: Whether Omnara should use this model's reasoning features. For OpenAI Responses, this also enables encrypted reasoning replay for stateless calls. Omitted keeps the current value.
        default_reasoning_effort:
          type: string
          description: Default reasoning effort to send for models/API formats that support effort-style reasoning controls. Requires supports_reasoning=true. When supported_reasoning_efforts is present, this value must be listed there.
        supported_reasoning_efforts:
          type: array
          description: Reasoning effort values this configured model accepts. Requires supports_reasoning=true when non-empty.
          items:
            type: string
        input_modalities:
          type: array
          description: Input types this configured model accepts. Omnara recognizes text, image, and file; an empty list leaves capabilities unspecified.
          items:
            type: string
        output_modalities:
          type: array
          description: Output types this configured model can return. Omnara currently consumes text output.
          items:
            type: string
        api_variant_options:
          $ref: '#/components/schemas/ModelAPIVariantOptions'
    ConfiguredModel:
      type: object
      additionalProperties: false
      required: [id, org_id, model_provider_config_id, management_kind, name, current_revision_id, provider_model_slug, context_window_tokens, max_output_tokens, supports_tools, supports_reasoning, default_reasoning_effort, supported_reasoning_efforts, input_modalities, output_modalities, api_variant_options, created_at, updated_at, revision_created_at]
      properties:
        id:
          $ref: '#/components/schemas/ConfiguredModelID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        model_provider_config_id:
          $ref: '#/components/schemas/ModelProviderConfigID'
        management_kind:
          $ref: '#/components/schemas/ManagementKind'
        name:
          $ref: '#/components/schemas/ResourceName'
          description: User-assigned configured model name used by agent YAML as model.name.
        current_revision_id:
          $ref: '#/components/schemas/ConfiguredModelRevisionID'
        provider_model_slug:
          type: string
          description: Exact provider model slug sent to the provider endpoint by the current revision.
        context_window_tokens:
          type: integer
          description: Total token window for this model, including input and output.
        max_output_tokens:
          type: integer
          description: Configured output-token ceiling for this model.
        default_max_output_tokens:
          type: [integer, "null"]
          description: Default per-request output-token cap sent to the provider unless an agent config overrides it.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: boolean
          description: Whether this configured model can receive tool definitions and emit tool calls.
        supports_reasoning:
          type: boolean
          description: Whether Omnara should use this model's reasoning features.
        default_reasoning_effort:
          type: string
          description: Default reasoning effort to send for models/API formats that support effort-style reasoning controls.
        supported_reasoning_efforts:
          type: array
          description: Reasoning effort values this configured model accepts.
          items:
            type: string
        input_modalities:
          type: array
          description: Input types this configured model accepts. Omnara recognizes text, image, and file; an empty list leaves capabilities unspecified.
          items:
            type: string
        output_modalities:
          type: array
          description: Output types this configured model can return.
          items:
            type: string
        api_variant_options:
          $ref: '#/components/schemas/ModelAPIVariantOptions'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
        revision_created_at:
          $ref: '#/components/schemas/Timestamp'
    ConfiguredModelList:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ConfiguredModel'
        next_cursor:
          type: [string, "null"]
    CreateProjectModelGrantRequest:
      type: object
      description: Grant a project access to a configured model. Optional fields can narrow the model's limits for this project; omitted fields inherit from the org-level configured model.
      additionalProperties: false
      required: [configured_model_id]
      properties:
        configured_model_id:
          $ref: '#/components/schemas/ConfiguredModelID'
        context_window_tokens:
          type: integer
          minimum: 2
          maximum: 2147483647
          description: Optional project token-window limit. Cannot exceed the configured model's current limit.
        max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Optional project output-token ceiling. Cannot exceed the configured model's ceiling.
        default_max_output_tokens:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Optional project default per-request output-token cap.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: boolean
          description: Optional project-level tool-use gate. Can disable tools, but cannot enable tools when the configured model does not support them.
        supports_reasoning:
          type: boolean
          description: Optional project-level reasoning gate. Can disable reasoning, but cannot enable reasoning when the configured model does not support it.
        default_reasoning_effort:
          type: string
          description: Optional project default reasoning effort.
        supported_reasoning_efforts:
          type: array
          description: Optional project subset of configured-model reasoning efforts. If this excludes the inherited default_reasoning_effort, set default_reasoning_effort on the grant too.
          items:
            type: string
        input_modalities:
          type: array
          description: Optional project subset of configured-model input types (text, image, or file). Empty or omitted means inherit.
          items:
            type: string
        output_modalities:
          type: array
          description: Optional project subset of configured-model output types. Empty or omitted means inherit.
          items:
            type: string
    UpdateProjectModelGrantRequest:
      type: object
      description: >-
        Update a project model grant's overrides. Omitted fields keep their current values. Null
        clears an override so the project inherits from the configured model; for arrays, an empty
        array clears the override.
      additionalProperties: false
      minProperties: 1
      properties:
        context_window_tokens:
          type: [integer, "null"]
          minimum: 1
          description: Project token-window limit. Cannot exceed the configured model's current limit.
        max_output_tokens:
          type: [integer, "null"]
          minimum: 1
          description: Project output-token ceiling. Cannot exceed the configured model's ceiling.
        default_max_output_tokens:
          type: [integer, "null"]
          minimum: 1
          description: Project default per-request output-token cap.
        default_cache_retention:
          anyOf:
            - $ref: '#/components/schemas/ModelCacheRetention'
            - type: "null"
        supports_tools:
          type: [boolean, "null"]
          description: Project-level tool-use gate. Can disable tools, but cannot enable tools when the configured model does not support them.
        supports_reasoning:
          type: [boolean, "null"]
          description: Project-level reasoning gate. Can disable reasoning, but cannot enable reasoning when the configured model does not support it.
        default_reasoning_effort:
          type: [string, "null"]
          description: Project default reasoning effort.
        supported_reasoning_efforts:
          type: array
          description: Project subset of configured-model reasoning efforts. If this excludes the inherited default_reasoning_effort, set default_reasoning_effort on the grant too.
          items:
            type: string
        input_modalities:
          type: array
          description: Project subset of configured-model input types.
          items:
            type: string
        output_modalities:
          type: array
          description: Project subset of configured-model output types.
          items:
            type: string
    ProjectModelGrant:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, configured_model_id, supported_reasoning_efforts, input_modalities, output_modalities, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ProjectModelGrantID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        configured_model_id:
          $ref: '#/components/schemas/ConfiguredModelID'
        context_window_tokens:
          type: [integer, "null"]
          description: Project token-window limit, or omitted/null to inherit from the configured model.
        max_output_tokens:
          type: [integer, "null"]
          description: Project output-token ceiling, or omitted/null to inherit from the configured model.
        default_max_output_tokens:
          type: [integer, "null"]
          description: Project default per-request output-token cap, or omitted/null to inherit from the configured model.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: [boolean, "null"]
          description: Project-level tool-use override, or omitted/null to inherit from the configured model.
        supports_reasoning:
          type: [boolean, "null"]
          description: Project-level reasoning override, or omitted/null to inherit from the configured model.
        default_reasoning_effort:
          type: string
          description: Project default reasoning effort, or omitted/empty to inherit from the configured model.
        supported_reasoning_efforts:
          type: array
          description: Project subset of configured-model reasoning efforts. Empty means inherit. When non-empty, default_reasoning_effort must resolve to one of these values.
          items:
            type: string
        input_modalities:
          type: array
          description: Project subset of configured-model input types (text, image, or file). Empty means inherit.
          items:
            type: string
        output_modalities:
          type: array
          description: Project subset of configured-model output types. Empty means inherit.
          items:
            type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ProjectModelGrantEnvelope:
      type: object
      additionalProperties: false
      required: [grant]
      properties:
        grant:
          $ref: '#/components/schemas/ProjectModelGrant'
    ListProjectModelGrantsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectModelGrantListItem'
        next_cursor:
          type: [string, "null"]
    ProjectModelGrantListItem:
      type: object
      additionalProperties: false
      required: [grant, model]
      properties:
        grant:
          $ref: '#/components/schemas/ProjectModelGrant'
        model:
          $ref: '#/components/schemas/ConfiguredModelSummary'
    ConfiguredModelSummary:
      type: object
      additionalProperties: false
      required: [id, org_id, model_provider_config_id, name, provider_config, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ConfiguredModelID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        model_provider_config_id:
          $ref: '#/components/schemas/ModelProviderConfigID'
        name:
          $ref: '#/components/schemas/ResourceName'
          description: User-assigned configured model name used by agent YAML as model.name.
        provider_config:
          $ref: '#/components/schemas/ResourceName'
          description: Name of the provider config that owns this model, used by agent YAML as model.provider_config.
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    MachinePoolID:
      type: string
      pattern: '^mpo_[a-z2-7]{26}$'
    MachineID:
      type: string
      pattern: '^mch_[a-z2-7]{26}$'
    ProjectMachineGrantID:
      type: string
      pattern: '^pmg_[a-z2-7]{26}$'
    ProjectMachinePoolGrantID:
      type: string
      pattern: '^pmpg_[a-z2-7]{26}$'
    MachineDaemonTokenID:
      type: string
      pattern: '^mdt_[a-z2-7]{26}$'
    SkillID:
      type: string
      pattern: '^skl_[a-z2-7]{26}$'
    SkillRevisionID:
      type: string
      pattern: '^skr_[a-z2-7]{26}$'
    SkillGrantID:
      type: string
      pattern: '^skg_[a-z2-7]{26}$'
    SecretID:
      type: string
      pattern: '^sec_[a-z2-7]{26}$'
    SecretGrantID:
      type: string
      pattern: '^sgr_[a-z2-7]{26}$'
    DaemonRuntimeID:
      type: string
      pattern: '^drt_[a-z2-7]{26}$'
    ProcessID:
      type: string
      pattern: '^prc_[a-z2-7]{26}$'
    ProcessActionID:
      type: string
      pattern: '^pac_[a-z2-7]{26}$'
    InstallationID:
      type: string
      pattern: '^inst_[a-z2-7]{26}$'
    UserID:
      type: string
      pattern: '^usr_[a-z2-7]{26}$'
    Timestamp:
      type: string
      format: date-time
    OrgSkillOwnerInput:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [org]
    ProjectSkillOwnerInput:
      type: object
      additionalProperties: false
      required: [kind, project_id]
      properties:
        kind:
          type: string
          enum: [project]
        project_id:
          $ref: '#/components/schemas/ProjectID'
    UserSkillOwnerInput:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [user]
    SkillOwnerInput:
      oneOf:
        - $ref: '#/components/schemas/OrgSkillOwnerInput'
        - $ref: '#/components/schemas/ProjectSkillOwnerInput'
        - $ref: '#/components/schemas/UserSkillOwnerInput'
      discriminator:
        propertyName: kind
        mapping:
          org: '#/components/schemas/OrgSkillOwnerInput'
          project: '#/components/schemas/ProjectSkillOwnerInput'
          user: '#/components/schemas/UserSkillOwnerInput'
    OrgSkillOwner:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [org]
    ProjectSkillOwner:
      type: object
      additionalProperties: false
      required: [kind, project_id]
      properties:
        kind:
          type: string
          enum: [project]
        project_id:
          $ref: '#/components/schemas/ProjectID'
    UserSkillOwner:
      type: object
      additionalProperties: false
      required: [kind, user_id]
      properties:
        kind:
          type: string
          enum: [user]
        user_id:
          $ref: '#/components/schemas/UserID'
    SkillOwner:
      oneOf:
        - $ref: '#/components/schemas/OrgSkillOwner'
        - $ref: '#/components/schemas/ProjectSkillOwner'
        - $ref: '#/components/schemas/UserSkillOwner'
      discriminator:
        propertyName: kind
        mapping:
          org: '#/components/schemas/OrgSkillOwner'
          project: '#/components/schemas/ProjectSkillOwner'
          user: '#/components/schemas/UserSkillOwner'
    CreateSkillRequest:
      type: object
      additionalProperties: false
      required: [owner, archive]
      properties:
        owner:
          $ref: '#/components/schemas/SkillOwnerInput'
        archive:
          type: string
          format: binary
    UpdateSkillRequest:
      type: object
      properties:
        archive:
          type: string
          format: binary
        skill_md:
          type: string
          description: >-
            Replacement SKILL.md content. Every other file in the current
            revision's archive is preserved unchanged.
      oneOf:
        - type: object
          additionalProperties: false
          required: [archive]
          properties:
            archive:
              type: string
              format: binary
        - type: object
          additionalProperties: false
          required: [skill_md]
          properties:
            skill_md:
              type: string
    Skill:
      type: object
      additionalProperties: false
      required: [id, org_id, owner, name, revision_id, revision, description, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/SkillID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        owner:
          $ref: '#/components/schemas/SkillOwner'
        name:
          $ref: '#/components/schemas/SkillName'
        revision_id:
          $ref: '#/components/schemas/SkillRevisionID'
        revision:
          type: integer
          format: int32
          minimum: 1
          description: Latest revision number of the skill.
        description:
          type: string
        skill_md:
          type: string
        files:
          type: array
          description: >-
            Files in the skill archive, including SKILL.md, with paths relative
            to the skill's top-level directory. Returned when fetching a single
            skill; omitted from list responses.
          items:
            $ref: '#/components/schemas/SkillFile'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    SkillFile:
      type: object
      additionalProperties: false
      required: [path, size]
      properties:
        path:
          type: string
        size:
          type: integer
          format: int64
          minimum: 0
    ListSkillsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Skill'
        next_cursor:
          type: [string, "null"]
    DirectSkillAvailability:
      type: object
      additionalProperties: false
      required: [source]
      properties:
        source:
          type: string
          enum: [direct]
    GrantedSkillAvailability:
      type: object
      additionalProperties: false
      required: [source, grant_id]
      properties:
        source:
          type: string
          enum: [grant]
        grant_id:
          $ref: '#/components/schemas/SkillGrantID'
    SkillAvailability:
      oneOf:
        - $ref: '#/components/schemas/DirectSkillAvailability'
        - $ref: '#/components/schemas/GrantedSkillAvailability'
      discriminator:
        propertyName: source
        mapping:
          direct: '#/components/schemas/DirectSkillAvailability'
          grant: '#/components/schemas/GrantedSkillAvailability'
    ProjectSkillAccess:
      type: object
      additionalProperties: false
      required: [skill, project_id, availability]
      properties:
        skill:
          $ref: '#/components/schemas/Skill'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        availability:
          $ref: '#/components/schemas/SkillAvailability'
    ListProjectSkillAccessesResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectSkillAccess'
        next_cursor:
          type: [string, "null"]
    SkillGrantCreateRequest:
      type: object
      additionalProperties: false
      required: [target_project_id]
      properties:
        target_project_id:
          $ref: '#/components/schemas/ProjectID'
    SkillGrant:
      type: object
      additionalProperties: false
      required: [id, org_id, skill_id, target_project_id, created_at]
      properties:
        id:
          $ref: '#/components/schemas/SkillGrantID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        skill_id:
          $ref: '#/components/schemas/SkillID'
        target_project_id:
          $ref: '#/components/schemas/ProjectID'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    SkillGrantListItem:
      type: object
      additionalProperties: false
      required: [grant, target_project]
      properties:
        grant:
          $ref: '#/components/schemas/SkillGrant'
        target_project:
          $ref: '#/components/schemas/Project'
    ListSkillGrantsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/SkillGrantListItem'
        next_cursor:
          type: [string, "null"]
    MCPOAuthStartRequest:
      type: object
      additionalProperties: false
      required: [owner, mcp_url, name]
      properties:
        owner:
          $ref: '#/components/schemas/SecretOwnerInput'
        mcp_url:
          type: string
          minLength: 1
        name:
          $ref: '#/components/schemas/ResourceName'
        return_to:
          type: string
        client_id:
          type: string
        client_secret:
          type: string
        scopes:
          type: array
          items:
            type: string
        metadata:
          $ref: '#/components/schemas/MCPOAuthStartMetadata'
    MCPOAuthStartMetadata:
      type: object
      description: User-supplied metadata for the stored secret. A restriction of Metadata that leaves room for one reserved pair - Omnara sets mcp_url on the secret to the flow's MCP endpoint URL, so the key is reserved and at most 15 user pairs are accepted.
      x-go-type: resourcemeta.Metadata
      x-go-type-import:
        path: github.com/omnara-ai/omnara/internal/resourcemeta
      x-go-type-skip-optional-pointer: true
      maxProperties: 15
      propertyNames:
        minLength: 1
        maxLength: 64
      not:
        required: [mcp_url]
      additionalProperties:
        type: string
        maxLength: 512
    MCPOAuthStartResponse:
      type: object
      additionalProperties: false
      required: [flow_id, authorization_url, expires_at]
      properties:
        flow_id:
          $ref: '#/components/schemas/MCPOAuthFlowID'
        authorization_url:
          type: string
          format: uri
        expires_at:
          $ref: '#/components/schemas/Timestamp'
    CreateIntegrationOAuthSetupRequest:
      type: object
      additionalProperties: false
      required: [client_id, client_secret, signing_secret]
      properties:
        provider:
          type: string
          default: slack
        client_id:
          type: string
          minLength: 1
        client_secret:
          type: string
          minLength: 1
        signing_secret:
          type: string
          minLength: 1
        return_to:
          type: string
    IntegrationInstall:
      type: object
      additionalProperties: false
      description: >-
        A provider app installation that connects an agent profile or a single agent to an external
        app. Exactly one of agent_profile_id and agent_id is set. Provider credentials are never
        returned.
      required: [id, org_id, project_id, provider, integration_kind, connection_mode, state, provider_tenant_id, provider_account_ref, provider_agent_display_name, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/IntegrationInstallID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_profile_id:
          $ref: '#/components/schemas/AgentProfileID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        provider:
          type: string
        integration_kind:
          type: string
        connection_mode:
          type: string
        state:
          type: string
          enum: [active, disabled]
        provider_tenant_id:
          type: string
        provider_account_ref:
          type: string
        provider_agent_display_name:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ListIntegrationInstallsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/IntegrationInstall'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    IntegrationOAuthSetup:
      type: object
      additionalProperties: false
      required: [provider, flow_id, oauth_url, redirect_uri, events_url, actions_url, expires_at]
      properties:
        provider:
          type: string
        flow_id:
          $ref: '#/components/schemas/IntegrationOAuthFlowID'
        oauth_url:
          type: string
          format: uri
        redirect_uri:
          type: string
          format: uri
        events_url:
          type: string
          format: uri
        actions_url:
          type: string
          format: uri
        expires_at:
          $ref: '#/components/schemas/Timestamp'
    CreateSlackSetupRequest:
      type: object
      additionalProperties: false
      required: [app_name, app_configuration_token]
      properties:
        app_name:
          type: string
          minLength: 1
          maxLength: 35
        app_configuration_token:
          type: string
          minLength: 1
        icon:
          $ref: '#/components/schemas/SlackSetupIcon'
        return_to:
          type: string
    SlackSetupIcon:
      type: object
      additionalProperties: false
      required: [data_base64]
      properties:
        filename:
          type: string
        data_base64:
          type: string
          minLength: 1
    SlackSetup:
      type: object
      additionalProperties: false
      required: [provider, flow_id, slack_app_id, oauth_url, redirect_uri, events_url, actions_url, expires_at]
      properties:
        provider:
          type: string
        flow_id:
          $ref: '#/components/schemas/IntegrationOAuthFlowID'
        slack_app_id:
          type: string
        oauth_url:
          type: string
          format: uri
        redirect_uri:
          type: string
          format: uri
        events_url:
          type: string
          format: uri
        actions_url:
          type: string
          format: uri
        expires_at:
          $ref: '#/components/schemas/Timestamp'
    CreateAgentConfigRequest:
      type: object
      additionalProperties: false
      required: [source, source_format]
      properties:
        source:
          type: string
          minLength: 1
        source_format:
          type: string
          enum: [yaml, json]
    UpdateAgentConfigRequest:
      description: >-
        Replaces a live agent's config. expected_current_config_id makes the
        change conditional on the agent still running that config, so
        concurrent editors get a conflict instead of silently overwriting each
        other.
      type: object
      additionalProperties: false
      required: [source, source_format]
      properties:
        source:
          type: string
          minLength: 1
        source_format:
          type: string
          enum: [yaml, json]
        expected_current_config_id:
          $ref: '#/components/schemas/AgentConfigID'
    ToolPermissionSelection:
      type: object
      additionalProperties: false
      required: [mode, parameters]
      properties:
        mode:
          type: string
        parameters:
          type: object
          additionalProperties: true
    ToolPermissionMode:
      type: object
      additionalProperties: false
      required: [name, label, description, parameters_schema]
      properties:
        name:
          type: string
        label:
          type: string
        description:
          type: string
        parameters_schema:
          type: object
          additionalProperties: true
    ToolPermissionProfile:
      type: object
      additionalProperties: false
      required: [default_permission, permission_modes]
      properties:
        default_permission:
          $ref: '#/components/schemas/ToolPermissionSelection'
        permission_modes:
          type: array
          items:
            $ref: '#/components/schemas/ToolPermissionMode'
    ToolCatalogEntry:
      type: object
      additionalProperties: false
      required: [name, description, default_permission, permission_modes]
      properties:
        name:
          type: string
        description:
          type: string
        default_permission:
          $ref: '#/components/schemas/ToolPermissionSelection'
        permission_modes:
          type: array
          items:
            $ref: '#/components/schemas/ToolPermissionMode'
    ToolCatalog:
      type: object
      additionalProperties: false
      required: [built_in_tools, custom_tool_permissions, mcp_tool_permissions]
      properties:
        built_in_tools:
          type: array
          items:
            $ref: '#/components/schemas/ToolCatalogEntry'
        custom_tool_permissions:
          $ref: '#/components/schemas/ToolPermissionProfile'
        mcp_tool_permissions:
          $ref: '#/components/schemas/ToolPermissionProfile'
    MCPRegistryHeader:
      type: object
      additionalProperties: false
      required: [name, is_required, is_secret]
      properties:
        name:
          type: string
        description:
          type: string
        is_required:
          type: boolean
        is_secret:
          type: boolean
    MCPRegistryRemote:
      type: object
      additionalProperties: false
      required: [type, url]
      properties:
        type:
          type: string
          description: Transport type as published in the registry. Always `streamable-http`; other transports are dropped when the snapshot is built.
        url:
          type: string
        headers:
          type: array
          items:
            $ref: '#/components/schemas/MCPRegistryHeader'
    MCPRegistryIcon:
      type: object
      additionalProperties: false
      required: [src]
      properties:
        src:
          type: string
          description: Absolute https URL of the icon image.
        mime_type:
          type: string
        sizes:
          type: array
          items:
            type: string
          description: Icon sizes as `WxH` strings, or `any` for scalable images.
        theme:
          type: string
          description: Theme the icon is intended for, `light` or `dark`, when the publisher specifies one.
    MCPRegistryServer:
      type: object
      additionalProperties: false
      required: [name, description, version, status, updated_at, remotes, icons]
      properties:
        name:
          type: string
          description: Reverse-DNS registry name, for example `io.github.owner/server`.
        title:
          type: string
        description:
          type: string
        version:
          type: string
        website_url:
          type: string
        status:
          type: string
        updated_at:
          type: string
          format: date-time
        remotes:
          type: array
          items:
            $ref: '#/components/schemas/MCPRegistryRemote'
        icons:
          type: array
          items:
            $ref: '#/components/schemas/MCPRegistryIcon'
    ListMCPServersResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MCPRegistryServer'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    MCPServerToolsRequest:
      type: object
      additionalProperties: false
      required: [url, auth]
      properties:
        url:
          type: string
          format: uri
          minLength: 1
          maxLength: 2048
          description: Streamable HTTP MCP endpoint. Must use HTTPS, except that HTTP is allowed for loopback hosts during local development.
        auth:
          $ref: '#/components/schemas/MCPServerAuth'
    MCPServerAuth:
      description: How Omnara authenticates to the MCP server. Secret references must be available to the project, either owned by it or granted to it.
      oneOf:
        - $ref: '#/components/schemas/MCPServerAuthNone'
        - $ref: '#/components/schemas/MCPServerAuthBearer'
        - $ref: '#/components/schemas/MCPServerAuthOAuth'
        - $ref: '#/components/schemas/MCPServerAuthSigV4'
      discriminator:
        propertyName: type
        mapping:
          none: '#/components/schemas/MCPServerAuthNone'
          bearer: '#/components/schemas/MCPServerAuthBearer'
          oauth: '#/components/schemas/MCPServerAuthOAuth'
          sigv4: '#/components/schemas/MCPServerAuthSigV4'
    MCPServerAuthNone:
      type: object
      additionalProperties: false
      required: [type]
      properties:
        type:
          type: string
          enum: [none]
    MCPServerAuthBearer:
      type: object
      additionalProperties: false
      required: [type, secret_id]
      properties:
        type:
          type: string
          enum: [bearer]
        secret_id:
          $ref: '#/components/schemas/SecretID'
          description: A generic secret whose value is sent as the bearer token.
    MCPServerAuthOAuth:
      type: object
      additionalProperties: false
      required: [type, secret_id]
      properties:
        type:
          type: string
          enum: [oauth]
        secret_id:
          $ref: '#/components/schemas/SecretID'
          description: An oauth_token_set secret. An expired access token is refreshed and the refreshed token set is stored as a new secret version.
    MCPServerAuthSigV4:
      type: object
      additionalProperties: false
      required: [type, secret_id, service, region]
      properties:
        type:
          type: string
          enum: [sigv4]
        secret_id:
          $ref: '#/components/schemas/SecretID'
          description: An aws_credentials secret used to sign requests.
        service:
          type: string
          minLength: 1
          maxLength: 64
          description: AWS signing service name, for example `bedrock-agentcore`.
        region:
          type: string
          minLength: 1
          maxLength: 64
          description: AWS signing region, for example `us-east-1`.
    MCPServerAuthRequiredError:
      type: object
      additionalProperties: false
      required: [error, code, auth]
      properties:
        error:
          type: string
          description: Human-readable error message. Do not match on it programmatically.
        code:
          type: string
          enum: [unprocessable]
        auth:
          $ref: '#/components/schemas/MCPServerAuthHint'
    MCPServerAuthHint:
      type: object
      additionalProperties: false
      required: [type]
      properties:
        type:
          type: string
          enum: [oauth, bearer]
          description: '`oauth` when the server advertises an OAuth authorization server per the MCP authorization spec; `bearer` when it rejects unauthenticated requests without OAuth metadata, which usually means a static API token.'
        scopes:
          type: array
          items:
            type: string
          description: Scopes the server requested or supports, when advertised.
        authorization_server:
          type: string
          description: Issuer URL of the OAuth authorization server, when advertised.
    MCPServerToolsResponse:
      type: object
      additionalProperties: false
      required: [protocol_version, server_info, tools]
      properties:
        protocol_version:
          type: string
          description: MCP protocol version negotiated with the server.
        server_info:
          $ref: '#/components/schemas/MCPServerInfo'
        tools:
          type: array
          items:
            $ref: '#/components/schemas/MCPServerTool'
    MCPServerInfo:
      type: object
      additionalProperties: false
      required: [name, version]
      properties:
        name:
          type: string
        version:
          type: string
        title:
          type: string
        description:
          type: string
        website_url:
          type: string
    MCPServerTool:
      type: object
      additionalProperties: false
      required: [name, input_schema]
      properties:
        name:
          type: string
          description: Tool name as advertised by the server. Referenced from agent config `mcp_servers.<key>.tools.<name>`.
        title:
          type: string
        description:
          type: string
        input_schema:
          type: object
          additionalProperties: true
          description: JSON Schema for the tool's arguments.
        output_schema:
          type: object
          additionalProperties: true
          description: JSON Schema for the tool's structured result, when the server advertises one.
        annotations:
          $ref: '#/components/schemas/MCPServerToolAnnotations'
    MCPServerToolAnnotations:
      type: object
      additionalProperties: false
      properties:
        title:
          type: string
        read_only_hint:
          type: boolean
        destructive_hint:
          type: boolean
        idempotent_hint:
          type: boolean
        open_world_hint:
          type: boolean
    AgentConfigModel:
      type: object
      additionalProperties: false
      required: [provider_config, name, provider_model_slug, configured_model_id, current_revision_id, api_format, api_variant, context_window_tokens, max_output_tokens, default_cache_retention, supports_tools, supports_reasoning, default_reasoning_effort, supported_reasoning_efforts, input_modalities, output_modalities]
      properties:
        provider_config:
          $ref: '#/components/schemas/ResourceName'
        name:
          $ref: '#/components/schemas/ResourceName'
          description: Configured model name selected by this agent config, rendered from the current configured model record.
        provider_model_slug:
          type: string
          description: Exact provider model slug on the configured model's current revision at response time.
        configured_model_id:
          $ref: '#/components/schemas/ConfiguredModelID'
        current_revision_id:
          $ref: '#/components/schemas/ConfiguredModelRevisionID'
        api_format:
          $ref: '#/components/schemas/ModelAPIFormat'
        api_variant:
          $ref: '#/components/schemas/ModelProviderAPIVariantResponse'
        context_window_tokens:
          type: integer
          description: Effective token window after configured-model, project-grant, and agent-config settings are applied.
        max_output_tokens:
          type: integer
          description: Effective largest output-token cap Omnara allows for this agent config.
        default_max_output_tokens:
          type: [integer, "null"]
          description: Effective per-request output-token cap sent to the provider.
        default_cache_retention:
          $ref: '#/components/schemas/ModelCacheRetention'
        supports_tools:
          type: boolean
        supports_reasoning:
          type: boolean
        default_reasoning_effort:
          type: string
        supported_reasoning_efforts:
          type: array
          items:
            type: string
        input_modalities:
          type: array
          items:
            type: string
        output_modalities:
          type: array
          items:
            type: string
    AgentConfig:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, effective_definition_hash, model, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentConfigID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        source:
          type: string
        source_format:
          type: string
          enum: [yaml, json]
        compiler_version:
          type: string
        effective_definition_hash:
          type: string
        model:
          $ref: '#/components/schemas/AgentConfigModel'
        instruction_hash:
          type: string
        warnings:
          type: array
          minItems: 1
          x-go-type-skip-optional-pointer: true
          description: Non-blocking diagnostics about the agent config.
          items:
            $ref: '#/components/schemas/Warning'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    CreateAgentProfileRequest:
      type: object
      additionalProperties: false
      required: [name, config]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        config:
          $ref: '#/components/schemas/AgentConfigID'
    UpdateAgentProfileRequest:
      type: object
      additionalProperties: false
      required: [config, expected_current_config_id]
      properties:
        config:
          $ref: '#/components/schemas/AgentConfigID'
        expected_current_config_id:
          $ref: '#/components/schemas/AgentConfigID'
    RenameAgentProfileRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
    AgentProfile:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, name, current_config_id, current_generation, current_config, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentProfileID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        name:
          $ref: '#/components/schemas/ResourceName'
        current_config_id:
          $ref: '#/components/schemas/AgentConfigID'
        current_generation:
          type: integer
          format: int32
        current_config:
          $ref: '#/components/schemas/AgentConfig'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ListAgentProfilesResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentProfile'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    AgentCronTriggerTarget:
      type: object
      additionalProperties: false
      required: [type, agent_id]
      properties:
        type:
          type: string
          enum: [agent]
        agent_id:
          $ref: '#/components/schemas/AgentID'
        delivery_mode:
          $ref: '#/components/schemas/CronTriggerDeliveryMode'
    AgentProfileCronTriggerTarget:
      type: object
      additionalProperties: false
      required: [type, agent_profile_id]
      properties:
        type:
          type: string
          enum: [profile]
        agent_profile_id:
          $ref: '#/components/schemas/AgentProfileID'
    CronTriggerTarget:
      oneOf:
        - $ref: '#/components/schemas/AgentCronTriggerTarget'
        - $ref: '#/components/schemas/AgentProfileCronTriggerTarget'
      discriminator:
        propertyName: type
        mapping:
          agent: '#/components/schemas/AgentCronTriggerTarget'
          profile: '#/components/schemas/AgentProfileCronTriggerTarget'
    CronExpression:
      type: string
      description: >-
        Standard five-field cron expression (minute, hour, day of month, month, day of week).
        `TZ=`/`CRON_TZ=` prefixes are rejected; set the `timezone` field instead.
      minLength: 9
      maxLength: 256
    CronTimezone:
      type: string
      description: IANA time zone the schedule is evaluated in.
      default: UTC
      maxLength: 64
    CronMessageTemplate:
      type: string
      description: >-
        Go text/template rendered on each firing to produce the message sent to the target. The
        template receives a `trigger` value with `name`, `fired_at`, and `last_fired_at` fields.
        Rendering is capped at 64 KiB of output and one second of wall-clock time, and `printf`
        width and precision specifiers are capped at 1024; a firing whose template fails to
        render is recorded in `failure_report` without sending a message.
      maxLength: 65536
    CronTriggerDeliveryMode:
      type: string
      enum: [queued, steering]
      description: >-
        Each firing sends a queued or steering message to the agent. Defaults to `queued` on creation;
        omitted updates preserve the current mode.
    CronTriggerFailureReport:
      type: object
      additionalProperties: false
      required: [message, will_retry, failed_at]
      properties:
        message:
          type: string
          description: Why the most recent failed firing did not deliver a message.
        will_retry:
          type: boolean
          description: Whether the firing will be retried after the claim lease expires.
        failed_at:
          $ref: '#/components/schemas/Timestamp'
    CreateCronTriggerRequest:
      type: object
      additionalProperties: false
      required: [name, target, cron, message_template]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        target:
          $ref: '#/components/schemas/CronTriggerTarget'
        cron:
          $ref: '#/components/schemas/CronExpression'
        timezone:
          $ref: '#/components/schemas/CronTimezone'
        message_template:
          $ref: '#/components/schemas/CronMessageTemplate'
        enabled:
          type: boolean
          default: true
    UpdateCronTriggerRequest:
      type: object
      additionalProperties: false
      properties:
        target:
          $ref: '#/components/schemas/CronTriggerTarget'
          description: Updates target options. The target type and ID cannot change. Omitted delivery_mode preserves the current mode.
        name:
          $ref: '#/components/schemas/ResourceName'
        cron:
          $ref: '#/components/schemas/CronExpression'
        timezone:
          $ref: '#/components/schemas/CronTimezone'
        message_template:
          $ref: '#/components/schemas/CronMessageTemplate'
        enabled:
          type: boolean
    CronTrigger:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, name, target, cron, timezone, message_template, enabled, last_fired_at, next_fire_at, failure_report, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/CronTriggerID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        name:
          $ref: '#/components/schemas/ResourceName'
        target:
          $ref: '#/components/schemas/CronTriggerTarget'
        cron:
          $ref: '#/components/schemas/CronExpression'
        timezone:
          $ref: '#/components/schemas/CronTimezone'
        message_template:
          $ref: '#/components/schemas/CronMessageTemplate'
        enabled:
          type: boolean
        last_fired_at:
          oneOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
          description: When the trigger last fired, or null if it has never fired.
        next_fire_at:
          oneOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
          description: Next scheduled firing, or null while the trigger is disabled.
        failure_report:
          oneOf:
            - $ref: '#/components/schemas/CronTriggerFailureReport'
            - type: "null"
          description: >-
            Most recent failed firing, or null if no firing has failed since the last
            successful firing.
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ListCronTriggersResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/CronTrigger'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    CreateAgentRequest:
      type: object
      additionalProperties: false
      required: [config]
      properties:
        profile:
          $ref: '#/components/schemas/AgentProfileID'
        config:
          $ref: '#/components/schemas/AgentConfigID'
        name:
          $ref: '#/components/schemas/AgentName'
          description: Optional agent name. Omit to inherit the profile name when present; send an empty string to leave the agent unnamed.
        message:
          type: string
    Agent:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, state, name, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_profile_id:
          $ref: '#/components/schemas/AgentProfileID'
        state:
          type: string
          enum: [active, archived]
        name:
          $ref: '#/components/schemas/AgentName'
        integration_target:
          $ref: '#/components/schemas/IntegrationTarget'
        current_config_id:
          $ref: '#/components/schemas/AgentConfigID'
        model:
          $ref: '#/components/schemas/AgentModel'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
        archived_at:
          $ref: '#/components/schemas/Timestamp'
    AgentModel:
      type: object
      additionalProperties: false
      required: [provider_config, name]
      properties:
        provider_config:
          $ref: '#/components/schemas/ResourceName'
        name:
          $ref: '#/components/schemas/ResourceName'
    IntegrationTarget:
      type: object
      additionalProperties: false
      required: [provider, provider_ref, provider_ref_kind, display_name]
      properties:
        provider:
          type: string
        provider_ref:
          type: string
        provider_ref_kind:
          type: string
        display_name:
          type: string
        provider_uri:
          type: string
          format: uri
    AgentMCPConnection:
      type: object
      additionalProperties: false
      required: [server_key, endpoint_url, state, initialize_error, created_at, updated_at]
      properties:
        server_key:
          type: string
        endpoint_url:
          type: string
        state:
          type: string
          enum: [initializing, ready, failed, expired]
        protocol_version:
          type: string
        initialize_error:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CurrentAgentResponse:
      type: object
      additionalProperties: false
      required: [agent]
      properties:
        agent:
          $ref: '#/components/schemas/Agent'
    GetAgentResponse:
      type: object
      additionalProperties: false
      required: [agent, machine_ids, mcp_connections]
      properties:
        agent:
          $ref: '#/components/schemas/Agent'
        machine_ids:
          description: Machines currently attached to the agent, in binding creation order.
          type: array
          items:
            $ref: '#/components/schemas/MachineID'
        mcp_connections:
          description: The agent's MCP server connections, ordered by server key.
          type: array
          items:
            $ref: '#/components/schemas/AgentMCPConnection'
    ListAgentsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Agent'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    AgentInputKind:
      type: string
      enum: [content, control, interaction_response, config_change]
      x-enum-varnames:
        - AgentInputKindContent
        - AgentInputKindControl
        - AgentInputKindInteractionResponse
        - AgentInputKindConfigChange
    AgentControlType:
      type: string
      enum: [cancel_current]
      x-enum-varnames:
        - AgentControlTypeCancelCurrent
    AgentSequence:
      description: Positive per-agent event, turn, or live-frame sequence.
      type: integer
      minimum: 1
      maximum: 9007199254740991
      x-go-type: int64
    AgentSequenceCursor:
      description: Non-negative agent timeline cursor.
      type: integer
      minimum: 0
      maximum: 9007199254740991
      x-go-type: int64
    AgentCount:
      description: Positive count within an agent timeline.
      type: integer
      minimum: 1
      maximum: 9007199254740991
      x-go-type: int64
    ModelStopReason:
      type: string
      enum: [end_turn, tool_use, max_tokens, refusal, content_filter, pause, context_window, unknown]
      x-enum-varnames:
        - ModelStopReasonEndTurn
        - ModelStopReasonToolUse
        - ModelStopReasonMaxTokens
        - ModelStopReasonRefusal
        - ModelStopReasonContentFilter
        - ModelStopReasonPause
        - ModelStopReasonContextWindow
        - ModelStopReasonUnknown
    ModelOutputStopReason:
      description: Stop reasons admitted as durable model-output events.
      type: string
      enum: [end_turn, tool_use, max_tokens, refusal, content_filter, error]
      x-enum-varnames:
        - ModelOutputStopReasonEndTurn
        - ModelOutputStopReasonToolUse
        - ModelOutputStopReasonMaxTokens
        - ModelOutputStopReasonRefusal
        - ModelOutputStopReasonContentFilter
        - ModelOutputStopReasonError
    ContentBlockMetadata:
      $ref: '#/components/schemas/Metadata'
      description: >-
        Arbitrary key-value metadata. Maximum 16 pairs, keys up to 64 characters,
        values must be strings of up to 512 characters. Keys beginning with `omnara_` are
        reserved for Omnara and may affect product behavior; use them only when
        intentionally invoking Omnara-defined behavior.
    TextContentBlock:
      type: object
      additionalProperties: false
      required: [type, text]
      properties:
        type:
          type: string
          enum: [text]
        text:
          type: string
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    InlineMediaContentBlock:
      type: object
      description: >-
        Files that pass validation are stored as artifacts. Model input always
        includes the artifact ID, whether or not the file contents can be sent
        directly. Text media must contain valid UTF-8 and is sent as text. Images
        and PDFs are sent directly when supported by the configured provider and
        model; unsupported combinations are rejected. Other binary documents are
        sent directly only to OpenAI Responses models with file input support.
        Chat Completions and Anthropic Messages receive the artifact ID and the
        filename, if provided, instead of the contents of those documents.
      additionalProperties: false
      required: [type, media_type, data]
      properties:
        type:
          type: string
          enum: [media]
        media_type:
          type: string
          enum:
            - image/png
            - image/jpeg
            - image/gif
            - image/webp
            - application/pdf
            - text/plain
            - text/markdown
            - text/csv
            - text/tab-separated-values
            - text/x-iif
            - application/msword
            - application/rtf
            - application/vnd.oasis.opendocument.text
            - application/vnd.apple.pages
            - application/vnd.apple.keynote
            - application/vnd.apple.iwork
            - application/vnd.ms-powerpoint
            - application/vnd.ms-excel
            - application/vnd.openxmlformats-officedocument.wordprocessingml.document
            - application/vnd.openxmlformats-officedocument.presentationml.presentation
            - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
        filename:
          type: string
          maxLength: 255
        data:
          type: string
          format: byte
          minLength: 1
          description: Base64-encoded file bytes. For text media types, the decoded bytes must be valid UTF-8.
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    MediaRefContentBlock:
      type: object
      additionalProperties: false
      required: [type, artifact_id]
      properties:
        type:
          type: string
          enum: [media_ref]
        artifact_id:
          $ref: '#/components/schemas/ArtifactID'
        exclude_from_model_context:
          type: boolean
          description: Whether the referenced artifact is excluded from later model context.
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    ReasoningContentBlock:
      type: object
      additionalProperties: false
      required: [type, text]
      properties:
        type:
          type: string
          enum: [reasoning]
        text:
          type: string
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    ErrorContentBlock:
      type: object
      additionalProperties: false
      required: [type, text]
      properties:
        type:
          type: string
          enum: [error]
        text:
          type: string
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    StructuredDataContentBlock:
      type: object
      additionalProperties: false
      required: [type, value]
      properties:
        type:
          type: string
          enum: [structured_data]
        value:
          $ref: '#/components/schemas/JSONBlob'
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    ModelToolCallContentBlock:
      type: object
      additionalProperties: false
      required: [type, tool_call_id, tool_type, name, input]
      properties:
        type:
          type: string
          enum: [tool_call]
        tool_call_id:
          $ref: '#/components/schemas/ToolCallID'
        tool_type:
          $ref: '#/components/schemas/ToolCallType'
        name:
          type: string
        input:
          $ref: '#/components/schemas/ToolInput'
        metadata:
          $ref: '#/components/schemas/ContentBlockMetadata'
    CreateAgentInputContentBlock:
      oneOf:
        - $ref: '#/components/schemas/TextContentBlock'
        - $ref: '#/components/schemas/InlineMediaContentBlock'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextContentBlock'
          media: '#/components/schemas/InlineMediaContentBlock'
    AgentInputContentBlock:
      oneOf:
        - $ref: '#/components/schemas/TextContentBlock'
        - $ref: '#/components/schemas/MediaRefContentBlock'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextContentBlock'
          media_ref: '#/components/schemas/MediaRefContentBlock'
    ModelOutputContentBlock:
      oneOf:
        - $ref: '#/components/schemas/TextContentBlock'
        - $ref: '#/components/schemas/MediaRefContentBlock'
        - $ref: '#/components/schemas/ReasoningContentBlock'
        - $ref: '#/components/schemas/ModelToolCallContentBlock'
        - $ref: '#/components/schemas/ErrorContentBlock'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextContentBlock'
          media_ref: '#/components/schemas/MediaRefContentBlock'
          reasoning: '#/components/schemas/ReasoningContentBlock'
          tool_call: '#/components/schemas/ModelToolCallContentBlock'
          error: '#/components/schemas/ErrorContentBlock'
    ToolResultContentBlock:
      oneOf:
        - $ref: '#/components/schemas/TextContentBlock'
        - $ref: '#/components/schemas/MediaRefContentBlock'
        - $ref: '#/components/schemas/StructuredDataContentBlock'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextContentBlock'
          media_ref: '#/components/schemas/MediaRefContentBlock'
          structured_data: '#/components/schemas/StructuredDataContentBlock'
    SubmitToolResultContentBlock:
      description: >-
        Submission accepts inline media. The persisted response exposes that
        media as a `media_ref` block.
      oneOf:
        - $ref: '#/components/schemas/TextContentBlock'
        - $ref: '#/components/schemas/InlineMediaContentBlock'
        - $ref: '#/components/schemas/StructuredDataContentBlock'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextContentBlock'
          media: '#/components/schemas/InlineMediaContentBlock'
          structured_data: '#/components/schemas/StructuredDataContentBlock'
    AgentInputDeliveryMode:
      type: string
      enum: [queued, steering, immediate]
    CreateAgentInputDeliveryMode:
      type: string
      enum: [queued, steering]
    AgentInput:
      type: object
      additionalProperties: false
      required: [id, agent_id, state, delivery_mode, input_kind, queued_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentInputID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        state:
          type: string
        delivery_mode:
          $ref: '#/components/schemas/AgentInputDeliveryMode'
        input_kind:
          $ref: '#/components/schemas/AgentInputKind'
        actor_id:
          description: Actor this input is attributed to. Absent when the input has no actor attribution.
          $ref: '#/components/schemas/ActorID'
        input_idempotency_key:
          type: string
          description: Idempotency key supplied when this content input was created. Absent for other input kinds.
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/AgentInputContentBlock'
        queued_at:
          $ref: '#/components/schemas/Timestamp'
    AgentMachineBindingState:
      type: string
      enum: [attached, released]
      x-enum-varnames:
        - AgentMachineBindingStateAttached
        - AgentMachineBindingStateReleased
    AgentMachineBindingKind:
      type: string
      enum: [explicit, pool]
      x-enum-varnames:
        - AgentMachineBindingKindExplicit
        - AgentMachineBindingKindPool
    AgentMachineBinding:
      type: object
      additionalProperties: false
      required: [id, project_id, agent_id, machine_id, machine_ref, binding_kind, state, description, cwd, env_overlay, secret_env_overlay, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentMachineBindingID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        machine_id:
          $ref: '#/components/schemas/MachineID'
        machine_ref:
          type: string
        binding_kind:
          $ref: '#/components/schemas/AgentMachineBindingKind'
        state:
          $ref: '#/components/schemas/AgentMachineBindingState'
        description:
          type: string
        cwd:
          type: string
        env_overlay:
          description: Env overlay applied to processes launched through this binding. For pool bindings it is also applied to the machine environment when the pool machine is provisioned, so the provider_options startup_script and the daemon run with it; connected machines keep their own environment. A null entry removes the key.
          type: object
          additionalProperties:
            type: [string, "null"]
        secret_env_overlay:
          description: Secret env overlay applied to processes launched through this binding. For pool bindings it is also applied to the machine environment when the pool machine is provisioned, so the provider_options startup_script and the daemon run with it; connected machines keep their own environment. A null entry removes the key.
          type: object
          additionalProperties:
            anyOf:
              - $ref: '#/components/schemas/SecretID'
              - type: "null"
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    MachineFailureReport:
      description: >-
        The machine's most recent daemon-reported failure. A single slot,
        overwritten by newer reports and cleared when the daemon recovers.
      type: object
      additionalProperties: false
      required: [stage, output_tail, output_truncated, reported_at]
      properties:
        stage:
          type: string
          enum: [startup_script, daemon_install, daemon_update, daemon_uninstall, daemon_uninstalled]
        exit_status:
          type: integer
        output_tail:
          type: string
        output_truncated:
          type: boolean
        daemon_version:
          type: string
        target_version:
          type: string
        reported_at:
          $ref: '#/components/schemas/Timestamp'
    LaunchAgentResponse:
      type: object
      additionalProperties: false
      required: [agent, agent_config, machine_bindings]
      properties:
        agent:
          $ref: '#/components/schemas/Agent'
        agent_config:
          $ref: '#/components/schemas/AgentConfig'
        machine_bindings:
          type: array
          items:
            $ref: '#/components/schemas/AgentMachineBinding'
        agent_input:
          $ref: '#/components/schemas/AgentInput'
    UpdateAgentConfigResponse:
      type: object
      additionalProperties: false
      required: [agent_config, agent_input, event_id]
      properties:
        agent_config:
          $ref: '#/components/schemas/AgentConfig'
        agent_input:
          $ref: '#/components/schemas/AgentInput'
        event_id:
          $ref: '#/components/schemas/AgentEventID'
    JSONBlob:
      description: Public JSON payload whose shape is determined by the event or interaction kind.
    ToolInput:
      description: Non-null JSON object containing the arguments emitted for a tool call.
      type: object
      additionalProperties: true
      x-go-type: json.RawMessage
      x-go-type-skip-optional-pointer: true
    Metadata:
      type: object
      description: Arbitrary key-value metadata. Maximum 16 pairs, keys up to 64 characters, values must be strings of up to 512 characters.
      x-go-type: resourcemeta.Metadata
      x-go-type-import:
        path: github.com/omnara-ai/omnara/internal/resourcemeta
      x-go-type-skip-optional-pointer: true
      maxProperties: 16
      propertyNames:
        minLength: 1
        maxLength: 64
      additionalProperties:
        type: string
        maxLength: 512
    MachineMetadata:
      type: object
      description: User-supplied metadata stored on a machine, provided directly or copied from the machine pool that provisions it. A restriction of Metadata that leaves room for one reserved pair - Omnara sets observed_platform on the machine to the platform reported by its daemon, so the key is reserved and at most 15 user pairs are accepted.
      x-go-type: resourcemeta.Metadata
      x-go-type-import:
        path: github.com/omnara-ai/omnara/internal/resourcemeta
      x-go-type-skip-optional-pointer: true
      maxProperties: 15
      propertyNames:
        minLength: 1
        maxLength: 64
      not:
        required: [observed_platform]
      additionalProperties:
        type: string
        maxLength: 512
    CreateAgentInputRequest:
      type: object
      additionalProperties: false
      required: [content_blocks]
      properties:
        content_blocks:
          type: array
          description: >-
            At most 20 inline media blocks per submission, each holding up to
            10 MiB of decoded media and up to 24 MiB decoded across the
            submission. Non-media blocks may hold up to 1 MiB combined. The
            whole request body is capped at 48 MiB.
          items:
            $ref: '#/components/schemas/CreateAgentInputContentBlock'
        delivery_mode:
          $ref: '#/components/schemas/CreateAgentInputDeliveryMode'
        cancel_open_interactions:
          type: boolean
          description: Only valid when delivery_mode is steering. When true, atomically cancels open interactions associated with the current turn's unfinished tool calls before creating the steering input. Their parent tool calls complete as canceled; the turn, runtime, and unrelated tool calls are preserved.
        actor:
          description: External actor to attribute this input to, upserted by (provider_tenant_id, provider_user_id) atomically with the input; a rejected request writes no actor. Only allowed for non-user principals; requests authenticated as a user must omit it and are attributed to the user's omnara actor. When a non-user request omits it, the input has no actor attribution.
          $ref: '#/components/schemas/ExternalActorParams'
    AgentInputEnvelope:
      type: object
      additionalProperties: false
      required: [agent_input]
      properties:
        agent_input:
          $ref: '#/components/schemas/AgentInput'
    ToolCallType:
      description: >-
        Identifies who manages execution. Built-in and MCP calls are
        platform-managed; custom calls wait for an external consumer to submit
        their result.
      type: string
      enum: [built_in, custom, mcp]
      x-enum-varnames: [ToolCallTypeBuiltIn, ToolCallTypeCustom, ToolCallTypeMCP]
    ToolCallState:
      description: >-
        Current lifecycle state. awaiting_authorization has not evaluated its
        permission mode; awaiting_permission has an open authorization prompt;
        ready is authorized and eligible to run; running has an active worker;
        waiting has durable work that will complete the call independently;
        completed is terminal and includes outcome and completed_at. Custom
        calls remain ready until a consumer submits their result.
      type: string
      enum: [awaiting_authorization, awaiting_permission, ready, running, waiting, completed]
      x-enum-varnames:
        - ToolCallStateAwaitingAuthorization
        - ToolCallStateAwaitingPermission
        - ToolCallStateReady
        - ToolCallStateRunning
        - ToolCallStateWaiting
        - ToolCallStateCompleted
    ToolCallOutcome:
      description: Terminal outcome, present only when state is completed.
      type: string
      enum: [succeeded, failed, denied, canceled]
      x-enum-varnames:
        - ToolCallOutcomeSucceeded
        - ToolCallOutcomeFailed
        - ToolCallOutcomeDenied
        - ToolCallOutcomeCanceled
    ToolCall:
      description: A model-emitted tool call together with its current lifecycle state.
      type: object
      additionalProperties: false
      required: [id, turn_id, provider_call_id, name, input, type, state, created_at]
      properties:
        id:
          $ref: '#/components/schemas/ToolCallID'
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        provider_call_id:
          type: string
        name:
          type: string
        input:
          $ref: '#/components/schemas/ToolInput'
        type:
          $ref: '#/components/schemas/ToolCallType'
        state:
          $ref: '#/components/schemas/ToolCallState'
        outcome:
          $ref: '#/components/schemas/ToolCallOutcome'
        completed_at:
          $ref: '#/components/schemas/Timestamp'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ToolCallUpdate:
      description: An ephemeral notification that a tool call entered a lifecycle state.
      type: object
      additionalProperties: false
      required: [tool_call_id, state]
      properties:
        tool_call_id:
          $ref: '#/components/schemas/ToolCallID'
        state:
          $ref: '#/components/schemas/ToolCallState'
    ListToolCallsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ToolCall'
        next_cursor:
          type: [string, "null"]
    SubmitToolCallResultRequest:
      type: object
      additionalProperties: false
      required: [outcome, content_blocks]
      properties:
        outcome:
          type: string
          enum: [succeeded, failed]
          description: Whether the custom tool call succeeded or failed.
        content_blocks:
          type: array
          description: >-
            At most 20 inline media blocks per submission, each holding up to
            10 MiB of decoded media and up to 24 MiB decoded across the
            submission. Non-media blocks may hold up to 1 MiB combined. The
            whole request body is capped at 48 MiB.
          items:
            $ref: '#/components/schemas/SubmitToolResultContentBlock'
    ToolResult:
      type: object
      additionalProperties: false
      required: [event_id, agent_id, tool_call_id, outcome, content_blocks, created_at]
      properties:
        event_id:
          $ref: '#/components/schemas/AgentEventID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        tool_call_id:
          $ref: '#/components/schemas/ToolCallID'
        outcome:
          $ref: '#/components/schemas/ToolCallOutcome'
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/ToolResultContentBlock'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    SubmitToolCallResultResponse:
      type: object
      additionalProperties: false
      required: [tool_call, tool_result]
      properties:
        tool_call:
          $ref: '#/components/schemas/ToolCall'
        tool_result:
          $ref: '#/components/schemas/ToolResult'
    AgentInputEvent:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, turn_id, turn_sequence, is_opening_event, sequence, event_kind, agent_input_id, input_kind, content_blocks, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentEventID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        turn_sequence:
          $ref: '#/components/schemas/AgentSequence'
        is_opening_event:
          type: boolean
        sequence:
          $ref: '#/components/schemas/AgentSequence'
        event_kind:
          type: string
          enum: [agent_input]
        agent_input_id:
          description: Matches the input that produced this event, allowing clients to correlate an input submission with its durable timeline admission.
          $ref: '#/components/schemas/AgentInputID'
        input_kind:
          $ref: '#/components/schemas/AgentInputKind'
        actor_id:
          description: Actor attributed to the input. Resolve details through the project actors endpoints.
          $ref: '#/components/schemas/ActorID'
        input_idempotency_key:
          type: string
          description: Echoes the Idempotency-Key of a content-input request so its sender can recognize the durable admission. Absent for other input kinds.
        control_type:
          $ref: '#/components/schemas/AgentControlType'
        interaction_id:
          description: Interaction answered by an interaction_response input.
          $ref: '#/components/schemas/AgentInteractionID'
        agent_config_id:
          description: Configuration selected by a config_change input.
          $ref: '#/components/schemas/AgentConfigID'
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/AgentInputContentBlock'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ModelOutputEvent:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, turn_id, turn_sequence, is_opening_event, sequence, event_kind, model_call_context_id, stop_reason, content_blocks, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentEventID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        turn_sequence:
          $ref: '#/components/schemas/AgentSequence'
        is_opening_event:
          type: boolean
          enum: [false]
          x-enum-varnames: [ModelOutputEventIsOpeningEventFalse]
        sequence:
          $ref: '#/components/schemas/AgentSequence'
        event_kind:
          type: string
          enum: [model_output]
        model_call_context_id:
          $ref: '#/components/schemas/ModelCallContextID'
        stop_reason:
          $ref: '#/components/schemas/ModelOutputStopReason'
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/ModelOutputContentBlock'
        usage:
          $ref: '#/components/schemas/ModelUsage'
        provider_metadata:
          type: object
          description: >-
            Facts the provider reported about this call, keyed by provider
            (for example `openrouter.provider` names the upstream that served
            an OpenRouter request). Present only when the provider reported
            something.
          x-go-type: json.RawMessage
          x-go-type-skip-optional-pointer: true
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ToolResultEvent:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, turn_id, turn_sequence, is_opening_event, sequence, event_kind, tool_call_id, outcome, content_blocks, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentEventID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        turn_sequence:
          $ref: '#/components/schemas/AgentSequence'
        is_opening_event:
          type: boolean
          enum: [false]
          x-enum-varnames: [ToolResultEventIsOpeningEventFalse]
        sequence:
          $ref: '#/components/schemas/AgentSequence'
        event_kind:
          type: string
          enum: [tool_result]
        tool_call_id:
          $ref: '#/components/schemas/ToolCallID'
        outcome:
          $ref: '#/components/schemas/ToolCallOutcome'
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/ToolResultContentBlock'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ContextCheckpointEvent:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, turn_id, turn_sequence, is_opening_event, sequence, event_kind, context_checkpoint_id, summarized_through_event_sequence, summary, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentEventID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        turn_sequence:
          $ref: '#/components/schemas/AgentSequence'
        is_opening_event:
          type: boolean
          enum: [false]
          x-enum-varnames: [ContextCheckpointEventIsOpeningEventFalse]
        sequence:
          $ref: '#/components/schemas/AgentSequence'
        event_kind:
          type: string
          enum: [context_checkpoint]
        context_checkpoint_id:
          $ref: '#/components/schemas/ContextCheckpointID'
        summarized_through_event_sequence:
          $ref: '#/components/schemas/AgentSequence'
        summary:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
    AgentEvent:
      oneOf:
        - $ref: '#/components/schemas/AgentInputEvent'
        - $ref: '#/components/schemas/ModelOutputEvent'
        - $ref: '#/components/schemas/ToolResultEvent'
        - $ref: '#/components/schemas/ContextCheckpointEvent'
      discriminator:
        propertyName: event_kind
        mapping:
          agent_input: '#/components/schemas/AgentInputEvent'
          model_output: '#/components/schemas/ModelOutputEvent'
          tool_result: '#/components/schemas/ToolResultEvent'
          context_checkpoint: '#/components/schemas/ContextCheckpointEvent'
    ModelOutputTextStreamBlock:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [text]
    ModelOutputThinkingStreamBlock:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [thinking]
    ModelOutputToolUseStreamBlock:
      type: object
      additionalProperties: false
      required: [kind, tool_call_id, tool_name]
      properties:
        kind:
          type: string
          enum: [tool_use]
        tool_call_id:
          description: Stable public ID shared with the eventual durable ToolCall when this is a tool_use block.
          $ref: '#/components/schemas/ToolCallID'
        tool_name:
          type: string
    ModelOutputStreamBlock:
      oneOf:
        - $ref: '#/components/schemas/ModelOutputTextStreamBlock'
        - $ref: '#/components/schemas/ModelOutputThinkingStreamBlock'
        - $ref: '#/components/schemas/ModelOutputToolUseStreamBlock'
      discriminator:
        propertyName: kind
        mapping:
          text: '#/components/schemas/ModelOutputTextStreamBlock'
          thinking: '#/components/schemas/ModelOutputThinkingStreamBlock'
          tool_use: '#/components/schemas/ModelOutputToolUseStreamBlock'
    ModelOutputBlockStartDelta:
      type: object
      additionalProperties: false
      required: [kind, block_index, block]
      properties:
        kind:
          type: string
          enum: [block_start]
        block_index:
          type: integer
          minimum: 0
        block:
          $ref: '#/components/schemas/ModelOutputStreamBlock'
    ModelOutputTextDelta:
      type: object
      additionalProperties: false
      required: [kind, block_index, delta]
      properties:
        kind:
          type: string
          enum: [text_delta]
        block_index:
          type: integer
          minimum: 0
        delta:
          type: string
    ModelOutputThinkingDelta:
      type: object
      additionalProperties: false
      required: [kind, block_index, delta]
      properties:
        kind:
          type: string
          enum: [thinking_delta]
        block_index:
          type: integer
          minimum: 0
        delta:
          type: string
    ModelOutputToolArgumentsDelta:
      type: object
      additionalProperties: false
      required: [kind, block_index, delta]
      properties:
        kind:
          type: string
          enum: [tool_arguments_delta]
        block_index:
          type: integer
          minimum: 0
        delta:
          type: string
    ModelOutputBlockStopDelta:
      type: object
      additionalProperties: false
      required: [kind, block_index]
      properties:
        kind:
          type: string
          enum: [block_stop]
        block_index:
          type: integer
          minimum: 0
    ModelUsage:
      type: object
      additionalProperties: false
      description: >-
        Token counts the provider reported for one model call. Cache and
        reasoning counts are omitted when the provider reported none.
      properties:
        input_tokens_total:
          type: integer
          minimum: 0
        uncached_input_tokens:
          type: integer
          minimum: 0
        output_tokens_total:
          type: integer
          minimum: 0
        reasoning_output_tokens:
          type: integer
          minimum: 0
        cache_read_input_tokens:
          type: integer
          minimum: 0
        cache_write_input_tokens:
          type: integer
          minimum: 0
    ModelOutputMessageStopDelta:
      type: object
      additionalProperties: false
      required: [kind, stop]
      properties:
        kind:
          type: string
          enum: [message_stop]
        stop:
          type: object
          additionalProperties: false
          required: [reason, usage]
          properties:
            reason:
              $ref: '#/components/schemas/ModelStopReason'
            usage:
              $ref: '#/components/schemas/ModelUsage'
    ModelOutputErrorDelta:
      type: object
      additionalProperties: false
      required: [kind, error]
      properties:
        kind:
          type: string
          enum: [error]
        error:
          type: object
          additionalProperties: false
          required: [message]
          properties:
            message:
              type: string
    ModelOutputStreamDelta:
      oneOf:
        - $ref: '#/components/schemas/ModelOutputBlockStartDelta'
        - $ref: '#/components/schemas/ModelOutputTextDelta'
        - $ref: '#/components/schemas/ModelOutputThinkingDelta'
        - $ref: '#/components/schemas/ModelOutputToolArgumentsDelta'
        - $ref: '#/components/schemas/ModelOutputBlockStopDelta'
        - $ref: '#/components/schemas/ModelOutputMessageStopDelta'
        - $ref: '#/components/schemas/ModelOutputErrorDelta'
      discriminator:
        propertyName: kind
        mapping:
          block_start: '#/components/schemas/ModelOutputBlockStartDelta'
          text_delta: '#/components/schemas/ModelOutputTextDelta'
          thinking_delta: '#/components/schemas/ModelOutputThinkingDelta'
          tool_arguments_delta: '#/components/schemas/ModelOutputToolArgumentsDelta'
          block_stop: '#/components/schemas/ModelOutputBlockStopDelta'
          message_stop: '#/components/schemas/ModelOutputMessageStopDelta'
          error: '#/components/schemas/ModelOutputErrorDelta'
    ModelOutputDelta:
      type: object
      additionalProperties: false
      required: [turn_id, model_call_context_id, seq, source_seq_start, source_seq_end, coalesced_count, event]
      properties:
        turn_id:
          $ref: '#/components/schemas/AgentTurnID'
        model_call_context_id:
          $ref: '#/components/schemas/ModelCallContextID'
        seq:
          $ref: '#/components/schemas/AgentSequence'
          description: Monotonic frame sequence within this model call context's preview stream, starting at 1. Delta frames carry no SSE id; gaps in seq mean dropped best-effort frames.
        source_seq_start:
          $ref: '#/components/schemas/AgentSequence'
          description: First provider stream event coalesced into this frame.
        source_seq_end:
          $ref: '#/components/schemas/AgentSequence'
          description: Last provider stream event coalesced into this frame.
        coalesced_count:
          $ref: '#/components/schemas/AgentCount'
          description: Number of provider stream events coalesced into this frame. A frame is intact only when this equals source_seq_end - source_seq_start + 1; a smaller count means events inside the range were dropped before coalescing.
        event:
          $ref: '#/components/schemas/ModelOutputStreamDelta'
    AgentEventStreamData:
      description: >-
        One JSON payload from the event stream: an authoritative durable event,
        a best-effort tool-call update, a best-effort model-output preview, or
        a stream-closing error. The wire response ends after an error payload;
        `service_unavailable` is retryable and other current codes are
        terminal.
      oneOf:
        - $ref: '#/components/schemas/AgentEvent'
        - $ref: '#/components/schemas/ToolCallUpdate'
        - $ref: '#/components/schemas/ModelOutputDelta'
        - $ref: '#/components/schemas/Error'
    ListAgentEventsResponse:
      type: object
      additionalProperties: false
      required: [data, next_after_sequence, has_more]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentEvent'
        next_after_sequence:
          $ref: '#/components/schemas/AgentSequenceCursor'
          description: Sequence to pass as after_sequence on the next request. Equals the request boundary when no events are returned.
        next_before_sequence:
          anyOf:
            - $ref: '#/components/schemas/AgentSequenceCursor'
            - type: "null"
          description: Sequence to pass as before_sequence for the next older page. Null when no older events remain or when paginating forward.
        has_more:
          type: boolean
          description: True when another immediate request in the requested pagination direction can return more currently available events.
    ListTurnEventsResponse:
      type: object
      additionalProperties: false
      required: [data, next_before_sequence]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentEvent'
        next_before_sequence:
          anyOf:
            - $ref: '#/components/schemas/AgentSequenceCursor'
            - type: "null"
          description: Pass this value as before_sequence to fetch older events, or null when this page reached the beginning of the turn.
    AgentTurn:
      type: object
      additionalProperties: false
      required: [id, agent_id, turn_sequence, event_count, opening_events, started_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentTurnID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        turn_sequence:
          $ref: '#/components/schemas/AgentSequence'
        event_count:
          $ref: '#/components/schemas/AgentCount'
        opening_events:
          type: array
          items:
            $ref: '#/components/schemas/AgentEvent'
        latest_event:
          $ref: '#/components/schemas/AgentEvent'
        latest_semantic_event:
          $ref: '#/components/schemas/AgentEvent'
        started_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ListAgentTurnsResponse:
      type: object
      additionalProperties: false
      required: [data, next_before_turn_sequence]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentTurn'
        next_before_turn_sequence:
          anyOf:
            - $ref: '#/components/schemas/AgentSequenceCursor'
            - type: "null"
          description: Pass this value as before_turn_sequence to fetch older turns, or null when this page reached the beginning of the agent's turns.
    CancelAgentRequest:
      type: object
      additionalProperties: false
      properties:
        actor:
          description: External actor to attribute this cancelation to, upserted by (provider_tenant_id, provider_user_id) atomically with the cancelation; a rejected request writes no actor. Only allowed for non-user principals; requests authenticated as a user must omit it and are attributed to the user's omnara actor.
          $ref: '#/components/schemas/ExternalActorParams'
    CancelAgentResponse:
      type: object
      additionalProperties: false
      required: [event, runtime_cancel_requested, affected]
      properties:
        event:
          anyOf:
            - $ref: '#/components/schemas/AgentEvent'
            - type: "null"
        runtime_cancel_requested:
          type: boolean
          description: Whether this request created or observed a durable runtime cancel request. Immediate delivery is best effort; runtime-lock renewal observes the durable request.
        affected:
          type: boolean
          description: Whether this request changed any cancelable work.
        actor_id:
          description: Actor the cancelation was attributed to. Absent when the request had no actor attribution.
          $ref: '#/components/schemas/ActorID'
    OKResponse:
      type: object
      additionalProperties: false
      required: [ok]
      properties:
        ok:
          type: boolean
    MoveQueuedBacklogInputRequest:
      type: object
      additionalProperties: false
      required: [position]
      properties:
        position:
          type: string
          enum: [front, back, before, after]
        anchor_input_id:
          $ref: '#/components/schemas/AgentInputID'
    PromoteQueuedInputToSteeringRequest:
      type: object
      additionalProperties: false
      properties:
        cancel_open_interactions:
          type: boolean
          description: When true, atomically cancels open interactions associated with the current turn's unfinished tool calls as this queued input becomes steering. Their parent tool calls complete as canceled; the turn, runtime, and unrelated tool calls are preserved.
    ListAgentInputsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentInput'
        next_cursor:
          type: [string, "null"]
    InteractionFormContextItem:
      type: object
      additionalProperties: false
      required: [label, value]
      properties:
        label:
          type: string
          minLength: 1
        value:
          type: string
          minLength: 1
    InteractionFormOption:
      type: object
      additionalProperties: false
      required: [label]
      properties:
        label:
          type: string
          minLength: 1
        allows_text:
          type: boolean
          default: false
          x-go-type-skip-optional-pointer: true
          description: Whether the answer may include optional companion text for this option.
    InteractionFormQuestion:
      type: object
      additionalProperties: false
      required: [prompt, options]
      properties:
        prompt:
          type: string
          minLength: 1
        multiple:
          type: boolean
          default: false
          x-go-type-skip-optional-pointer: true
          description: Whether the answer may select more than one option.
        options:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/InteractionFormOption'
    InteractionForm:
      type: object
      additionalProperties: false
      required: [title, questions]
      properties:
        title:
          type: string
          minLength: 1
        context:
          type: array
          items:
            $ref: '#/components/schemas/InteractionFormContextItem'
        questions:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/InteractionFormQuestion'
    InteractionAnswer:
      type: object
      additionalProperties: false
      required: [option_indices]
      properties:
        option_indices:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: integer
            minimum: 0
        text:
          type: string
          x-go-type-skip-optional-pointer: true
          description: Optional companion text when the selected option allows it.
    InteractionResolution:
      type: object
      additionalProperties: false
      required: [answers]
      properties:
        answers:
          type: array
          minItems: 1
          description: Answers in the same order as the interaction form's questions.
          items:
            $ref: '#/components/schemas/InteractionAnswer'
    AgentInteractionKind:
      type: string
      enum: [permission, question]
      x-enum-varnames:
        - AgentInteractionKindPermission
        - AgentInteractionKindQuestion
    AgentInteractionState:
      type: string
      enum: [open, resolved, canceled]
      x-enum-varnames:
        - AgentInteractionStateOpen
        - AgentInteractionStateResolved
        - AgentInteractionStateCanceled
    ResolveAgentInteractionRequest:
      type: object
      additionalProperties: false
      required: [answers]
      properties:
        answers:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/InteractionAnswer'
        actor:
          description: External actor to attribute to the generated interaction_response agent input, upserted by (provider_tenant_id, provider_user_id) atomically with the resolution; a rejected request writes no actor. Only allowed for non-user principals; requests authenticated as a user must omit it and are attributed to the user's omnara actor. When a non-user request omits it, the generated input has no actor attribution.
          $ref: '#/components/schemas/ExternalActorParams'
    AgentInteraction:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, tool_call_id, interaction_kind, state, request, created_at]
      properties:
        id:
          $ref: '#/components/schemas/AgentInteractionID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        tool_call_id:
          description: The tool call that is waiting on this interaction — the guarded tool for a permission, or the ask_question call for a question.
          $ref: '#/components/schemas/ToolCallID'
        tool_name:
          type: string
          description: The tool whose invocation a permission interaction guards. Present only when interaction_kind is permission.
        interaction_kind:
          $ref: '#/components/schemas/AgentInteractionKind'
        state:
          $ref: '#/components/schemas/AgentInteractionState'
        request:
          $ref: '#/components/schemas/InteractionForm'
        resolution:
          $ref: '#/components/schemas/InteractionResolution'
        resolved_by_input_id:
          description: The agent input that resolved the interaction — the submitted response, the content input that superseded it, or the cancel control input. Absent on open interactions and on system resolutions such as prompt delivery failure. The input's actor_id attributes the resolution.
          $ref: '#/components/schemas/AgentInputID'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        resolved_at:
          $ref: '#/components/schemas/Timestamp'
    ActorProvider:
      type: string
      description: omnara for project members, an integration provider such as slack, or external for API-managed actors.
      enum: [omnara, slack, external]
      x-enum-varnames:
        - ActorProviderOmnara
        - ActorProviderSlack
        - ActorProviderExternal
    Actor:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, provider, provider_user_id, metadata, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ActorID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        provider:
          $ref: '#/components/schemas/ActorProvider'
        provider_tenant_id:
          type: string
        provider_user_id:
          type: string
        display_name:
          type: string
        metadata:
          $ref: '#/components/schemas/Metadata'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ExternalActorParams:
      type: object
      description: Identity and attributes of an external actor. Actors are upserted by (provider_tenant_id, provider_user_id) with the external provider. Omitted attributes keep their stored values; provided attributes are overwritten, including empty values. omnara actors are implicit and integration providers own their own actor identities.
      additionalProperties: false
      required: [provider_user_id]
      properties:
        provider_tenant_id:
          type: string
          minLength: 1
          maxLength: 128
        provider_user_id:
          type: string
          minLength: 1
          maxLength: 128
        display_name:
          type: string
          maxLength: 256
        metadata:
          $ref: '#/components/schemas/Metadata'
    ListActorsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Actor'
        next_cursor:
          type: [string, "null"]
    ListAgentInteractionsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/AgentInteraction'
        next_cursor:
          type: [string, "null"]
    OrgSecretOwnerInput:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [org]
    ProjectSecretOwnerInput:
      type: object
      additionalProperties: false
      required: [kind, project_id]
      properties:
        kind:
          type: string
          enum: [project]
        project_id:
          $ref: '#/components/schemas/ProjectID'
    UserSecretOwnerInput:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [user]
    SecretOwnerInput:
      oneOf:
        - $ref: '#/components/schemas/OrgSecretOwnerInput'
        - $ref: '#/components/schemas/ProjectSecretOwnerInput'
        - $ref: '#/components/schemas/UserSecretOwnerInput'
      discriminator:
        propertyName: kind
        mapping:
          org: '#/components/schemas/OrgSecretOwnerInput'
          project: '#/components/schemas/ProjectSecretOwnerInput'
          user: '#/components/schemas/UserSecretOwnerInput'
    OrgSecretOwner:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          type: string
          enum: [org]
    ProjectSecretOwner:
      type: object
      additionalProperties: false
      required: [kind, project_id]
      properties:
        kind:
          type: string
          enum: [project]
        project_id:
          $ref: '#/components/schemas/ProjectID'
    UserSecretOwner:
      type: object
      additionalProperties: false
      required: [kind, user_id]
      properties:
        kind:
          type: string
          enum: [user]
        user_id:
          $ref: '#/components/schemas/UserID'
    SecretOwner:
      oneOf:
        - $ref: '#/components/schemas/OrgSecretOwner'
        - $ref: '#/components/schemas/ProjectSecretOwner'
        - $ref: '#/components/schemas/UserSecretOwner'
      discriminator:
        propertyName: kind
        mapping:
          org: '#/components/schemas/OrgSecretOwner'
          project: '#/components/schemas/ProjectSecretOwner'
          user: '#/components/schemas/UserSecretOwner'
    GenericSecretMaterial:
      type: object
      additionalProperties: false
      required: [kind, value]
      properties:
        kind:
          type: string
          enum: [generic]
        value:
          type: string
          minLength: 1
    OAuthRefreshSecretMaterial:
      type: object
      additionalProperties: false
      required: [refresh_token, token_endpoint, client_id, resource]
      properties:
        refresh_token:
          type: string
          minLength: 1
        token_endpoint:
          type: string
          format: uri
          minLength: 1
          description: Must use HTTPS, except that HTTP is allowed for loopback hosts during local development.
        client_id:
          type: string
          minLength: 1
        client_secret:
          type: string
          minLength: 1
        resource:
          type: string
          minLength: 1
    OAuthTokenSetSecretMaterial:
      type: object
      additionalProperties: false
      required: [kind, access_token]
      properties:
        kind:
          type: string
          enum: [oauth_token_set]
        access_token:
          type: string
          minLength: 1
        access_token_expires_in_seconds:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        refresh:
          $ref: '#/components/schemas/OAuthRefreshSecretMaterial'
        id_token:
          type: string
          minLength: 1
        mcp_url:
          type: string
          minLength: 1
        scopes:
          type: string
          minLength: 1
        token_type:
          type: string
          minLength: 1
    AWSCredentialsSecretMaterial:
      type: object
      additionalProperties: false
      required: [kind, access_key_id, secret_access_key]
      properties:
        kind:
          type: string
          enum: [aws_credentials]
        access_key_id:
          type: string
          minLength: 1
        secret_access_key:
          type: string
          minLength: 1
        session_token:
          type: string
          minLength: 1
        role_arn:
          type: string
          minLength: 1
        external_id:
          type: string
          minLength: 1
          description: Requires role_arn.
    SecretMaterial:
      oneOf:
        - $ref: '#/components/schemas/GenericSecretMaterial'
        - $ref: '#/components/schemas/OAuthTokenSetSecretMaterial'
        - $ref: '#/components/schemas/AWSCredentialsSecretMaterial'
      discriminator:
        propertyName: kind
        mapping:
          generic: '#/components/schemas/GenericSecretMaterial'
          oauth_token_set: '#/components/schemas/OAuthTokenSetSecretMaterial'
          aws_credentials: '#/components/schemas/AWSCredentialsSecretMaterial'
    CreateSecretRequest:
      type: object
      additionalProperties: false
      required: [owner, name, material]
      properties:
        owner:
          $ref: '#/components/schemas/SecretOwnerInput'
        name:
          $ref: '#/components/schemas/ResourceName'
        metadata:
          $ref: '#/components/schemas/Metadata'
        material:
          $ref: '#/components/schemas/SecretMaterial'
    UpdateSecretRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        metadata:
          $ref: '#/components/schemas/Metadata'
    SecretVersionRequest:
      type: object
      additionalProperties: false
      required: [material]
      properties:
        material:
          $ref: '#/components/schemas/SecretMaterial'
    SecretGrantCreateRequest:
      type: object
      additionalProperties: false
      required: [target_project_id]
      properties:
        target_project_id:
          $ref: '#/components/schemas/ProjectID'
    SecretKind:
      type: string
      enum: [generic, oauth_token_set, slack_app_credentials, aws_credentials]
      x-enum-varnames:
        - SecretKindGeneric
        - SecretKindOAuthTokenSet
        - SecretKindSlackAppCredentials
        - SecretKindAWSCredentials
    Secret:
      type: object
      additionalProperties: false
      required: [id, org_id, management_kind, owner, name, kind, metadata, current_version_number, payload_keys, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/SecretID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        management_kind:
          $ref: '#/components/schemas/ManagementKind'
        owner:
          $ref: '#/components/schemas/SecretOwner'
        name:
          $ref: '#/components/schemas/ResourceName'
        kind:
          $ref: '#/components/schemas/SecretKind'
        metadata:
          $ref: '#/components/schemas/Metadata'
        current_version_number:
          type: integer
          format: int32
        payload_keys:
          type: array
          items:
            type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    ListSecretsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Secret'
        next_cursor:
          type: [string, "null"]
    DirectSecretAvailability:
      type: object
      additionalProperties: false
      required: [source, project_id]
      properties:
        source:
          type: string
          enum: [direct]
        project_id:
          $ref: '#/components/schemas/ProjectID'
    GrantedSecretAvailability:
      type: object
      additionalProperties: false
      required: [source, project_id, grant_id]
      properties:
        source:
          type: string
          enum: [grant]
        project_id:
          $ref: '#/components/schemas/ProjectID'
        grant_id:
          $ref: '#/components/schemas/SecretGrantID'
    SecretAvailability:
      oneOf:
        - $ref: '#/components/schemas/DirectSecretAvailability'
        - $ref: '#/components/schemas/GrantedSecretAvailability'
      discriminator:
        propertyName: source
        mapping:
          direct: '#/components/schemas/DirectSecretAvailability'
          grant: '#/components/schemas/GrantedSecretAvailability'
    ProjectSecretAccess:
      type: object
      additionalProperties: false
      required: [secret, availability]
      properties:
        secret:
          $ref: '#/components/schemas/Secret'
        availability:
          $ref: '#/components/schemas/SecretAvailability'
    ListProjectSecretAccessesResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectSecretAccess'
        next_cursor:
          type: [string, "null"]
    SecretGrant:
      type: object
      additionalProperties: false
      required: [id, org_id, secret_id, target_project_id, created_at]
      properties:
        id:
          $ref: '#/components/schemas/SecretGrantID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        secret_id:
          $ref: '#/components/schemas/SecretID'
        target_project_id:
          $ref: '#/components/schemas/ProjectID'
        created_at:
          $ref: '#/components/schemas/Timestamp'
    SecretGrantListItem:
      type: object
      additionalProperties: false
      required: [grant, target_project]
      properties:
        grant:
          $ref: '#/components/schemas/SecretGrant'
        target_project:
          $ref: '#/components/schemas/Project'
    ListSecretGrantsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/SecretGrantListItem'
        next_cursor:
          type: [string, "null"]
    CreateOrganizationRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
    CreateOrganizationResponse:
      type: object
      additionalProperties: false
      required: [org, project, membership]
      properties:
        org:
          $ref: '#/components/schemas/Organization'
        project:
          $ref: '#/components/schemas/Project'
        membership:
          $ref: '#/components/schemas/OrganizationMembership'
    Organization:
      type: object
      additionalProperties: false
      required: [id, name, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    OrganizationMembership:
      type: object
      additionalProperties: false
      required: [org_id, user_id, role, created_at]
      properties:
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        user_id:
          $ref: '#/components/schemas/UserID'
        role:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
    OrgInvitation:
      type: object
      additionalProperties: false
      required: [id, org_id, org_name, email, org_role, created_at]
      properties:
        id:
          $ref: '#/components/schemas/OrgInvitationID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        org_name:
          $ref: '#/components/schemas/ResourceName'
        email:
          type: string
          format: email
        org_role:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ListOrgInvitationsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/OrgInvitation'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    CreateOrgInvitationRequest:
      type: object
      additionalProperties: false
      required: [email, role]
      properties:
        email:
          type: string
          format: email
        role:
          type: string
    CreatePersonalAccessTokenRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
    PersonalAccessToken:
      type: object
      additionalProperties: false
      required: [id, user_id, name, token_id, created_at, last_used_at, revoked_at]
      properties:
        id:
          $ref: '#/components/schemas/PersonalAccessTokenID'
        user_id:
          $ref: '#/components/schemas/UserID'
        name:
          $ref: '#/components/schemas/ResourceName'
        token_id:
          type: string
          description: Stable non-secret display identifier. It is not embedded in the bearer token.
        created_at:
          $ref: '#/components/schemas/Timestamp'
        last_used_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        revoked_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
    CreatePersonalAccessTokenResponse:
      type: object
      additionalProperties: false
      required: [token, token_record]
      properties:
        token:
          type: string
          minLength: 1
          description: Opaque bearer credential.
        token_record:
          $ref: '#/components/schemas/PersonalAccessToken'
    OrgAPIKeyRole:
      type: string
      enum: [admin, member]
      description: The key's org role. Org API keys can never hold the owner role.
    OrgAPIKey:
      type: object
      additionalProperties: false
      required: [id, org_id, name, token_id, org_role, created_by_user_id, created_at, updated_at, last_used_at, revoked_at]
      properties:
        id:
          $ref: '#/components/schemas/OrgAPIKeyID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        token_id:
          type: string
          description: Stable non-secret display identifier. It is not embedded in the bearer token.
        org_role:
          type: string
          description: The key's org role (admin or member). Empty for revoked keys.
        created_by_user_id:
          $ref: '#/components/schemas/UserID'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
        last_used_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        revoked_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
    CreateOrgAPIKeyRequest:
      type: object
      additionalProperties: false
      required: [name, org_role]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        org_role:
          $ref: '#/components/schemas/OrgAPIKeyRole'
    CreateOrgAPIKeyResponse:
      type: object
      additionalProperties: false
      required: [token, api_key]
      properties:
        token:
          type: string
          minLength: 1
          description: Opaque bearer credential.
        api_key:
          $ref: '#/components/schemas/OrgAPIKey'
    UpdateOrgAPIKeyRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        org_role:
          $ref: '#/components/schemas/OrgAPIKeyRole'
    ListOrgAPIKeysResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/OrgAPIKey'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    Artifact:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, agent_id, created_at]
      properties:
        id:
          $ref: '#/components/schemas/ArtifactID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        agent_id:
          $ref: '#/components/schemas/AgentID'
        content_type:
          type: string
        filename:
          type: string
        digest:
          type: string
        size_bytes:
          type: integer
          format: int64
        created_at:
          $ref: '#/components/schemas/Timestamp'
    CreateMachinePoolRequest:
      x-go-type: CreateMachinePoolRequestBase
      allOf:
        - $ref: '#/components/schemas/CreateMachinePoolRequestBase'
        - oneOf:
            - type: object
              required: [provider, default_machine_cpu, default_machine_memory_mb, max_total_cpu, max_total_memory_mb, max_machine_cpu, max_machine_memory_mb]
              properties:
                provider:
                  type: string
                  enum: [unikraft]
                default_machine_cpu:
                  type: integer
                  format: int32
                default_machine_memory_mb:
                  type: integer
                  format: int32
                max_total_cpu:
                  type: integer
                  format: int32
                max_total_memory_mb:
                  type: integer
                  format: int32
                max_machine_cpu:
                  type: integer
                  format: int32
                max_machine_memory_mb:
                  type: integer
                  format: int32
            - type: object
              required: [provider, max_total_cpu, max_total_memory_mb, max_machine_cpu, max_machine_memory_mb]
              properties:
                provider:
                  type: string
                  enum: [daytona]
                max_total_cpu:
                  type: integer
                  format: int32
                max_total_memory_mb:
                  type: integer
                  format: int32
                max_machine_cpu:
                  type: integer
                  format: int32
                max_machine_memory_mb:
                  type: integer
                  format: int32
            - type: object
              required: [provider, default_machine_memory_mb, max_total_memory_mb, max_machine_memory_mb]
              properties:
                provider:
                  type: string
                  enum: [blaxel]
                default_machine_memory_mb:
                  type: integer
                  format: int32
                max_total_memory_mb:
                  type: integer
                  format: int32
                max_machine_memory_mb:
                  type: integer
                  format: int32
              not:
                anyOf:
                  - required: [default_machine_cpu]
                  - required: [max_total_cpu]
                  - required: [min_machine_cpu]
                  - required: [max_machine_cpu]
    CreateMachinePoolRequestBase:
      type: object
      additionalProperties: false
      required: [name, provider, default_machine_provider_options, provider_auth_secret_id, max_total_machines]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        provider:
          type: string
          minLength: 1
        default_machine_cpu:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env:
          description: Default environment for pool machines. A machine's environment, including resolved secret_env values, is applied to the provider machine at provisioning, so the provider_options startup_script and the daemon run with it, and is resolved again for each process at launch.
          type: object
          additionalProperties:
            type: string
        default_machine_secret_env:
          description: Default secret environment for pool machines, mapping env names to generic secret references. References are resolved to secret values wherever the machine environment is applied.
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        default_machine_provider_options:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        provider_config:
          type: object
          additionalProperties: true
        provider_auth_secret_id:
          $ref: '#/components/schemas/SecretID'
        runtime_protection_enabled:
          description: Whether Omnara should delete a pool machine when its provider remains running after its daemon becomes inactive. Defaults to false when omitted.
          type: boolean
          default: false
        max_total_machines:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine from this pool. Omit to leave the pool default unset; a grant or agent source may still override it.
          type: integer
          format: int32
          minimum: 5
          maximum: 2147483647
        metadata:
          $ref: '#/components/schemas/MachineMetadata'
    UpdateMachinePoolRequest:
      type: object
      additionalProperties: false
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        default_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env:
          description: Default environment for pool machines. A machine's environment, including resolved secret_env values, is applied to the provider machine at provisioning, so the provider_options startup_script and the daemon run with it, and is resolved again for each process at launch.
          type: object
          additionalProperties:
            type: string
        default_machine_secret_env:
          description: Default secret environment for pool machines, mapping env names to generic secret references. References are resolved to secret values wherever the machine environment is applied.
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        default_machine_provider_options:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        provider_config:
          type: object
          additionalProperties: true
        provider_auth_secret_id:
          $ref: '#/components/schemas/SecretID'
        runtime_protection_enabled:
          description: Whether Omnara should delete a pool machine when its provider remains running after its daemon becomes inactive.
          type: boolean
        max_total_machines:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine from this pool. Null clears the pool default; omitted leaves it unchanged.
          type: [integer, "null"]
          format: int32
          minimum: 5
          maximum: 2147483647
        metadata:
          $ref: '#/components/schemas/MachineMetadata'
    MachinePool:
      type: object
      additionalProperties: false
      required: [id, org_id, name, management_kind, description, provider, default_machine_cpu, default_machine_memory_mb, default_machine_env, default_machine_secret_env, default_machine_provider_options, default_cwd, provider_config, runtime_protection_enabled, max_total_machines, max_total_cpu, max_total_memory_mb, min_machine_cpu, min_machine_memory_mb, max_machine_cpu, max_machine_memory_mb, delete_after_idle_minutes, metadata, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/MachinePoolID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        management_kind:
          $ref: '#/components/schemas/ManagementKind'
        description:
          type: string
        provider:
          type: string
        default_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env:
          description: Default environment for pool machines. A machine's environment, including resolved secret_env values, is applied to the provider machine at provisioning, so the provider_options startup_script and the daemon run with it, and is resolved again for each process at launch.
          type: object
          additionalProperties:
            type: string
        default_machine_secret_env:
          description: Default secret environment for pool machines, mapping env names to generic secret references. References are resolved to secret values wherever the machine environment is applied.
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        default_machine_provider_options:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        provider_auth_secret_id:
          $ref: '#/components/schemas/SecretID'
        provider_config:
          type: object
          additionalProperties: true
        runtime_protection_enabled:
          description: Whether Omnara deletes this pool's machines when the provider remains running after the daemon becomes inactive.
          type: boolean
        max_total_machines:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine from this pool, or null when the pool default is unset.
          type: [integer, "null"]
          format: int32
          minimum: 5
          maximum: 2147483647
        metadata:
          $ref: '#/components/schemas/Metadata'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
        usage:
          description: Current quota-consuming usage. Populated when the machine pool is returned by the list endpoint.
          $ref: '#/components/schemas/MachinePoolUsage'
    MachinePoolUsage:
      type: object
      additionalProperties: false
      required: [machines, cpu, memory_mb]
      properties:
        machines:
          type: integer
          format: int32
          minimum: 0
        cpu:
          type: integer
          format: int64
          minimum: 0
        memory_mb:
          type: integer
          format: int64
          minimum: 0
    ListMachinePoolsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MachinePool'
        next_cursor:
          type: [string, "null"]
    MachineSourceKind:
      type: string
      enum: [byo, pool]
      x-enum-varnames:
        - MachineSourceKindBYO
        - MachineSourceKindPool
    MachineLifecycleState:
      type: string
      enum: [provisioning, provision_failed, active, deleting, delete_failed, deleted]
      x-enum-varnames:
        - MachineLifecycleStateProvisioning
        - MachineLifecycleStateProvisionFailed
        - MachineLifecycleStateActive
        - MachineLifecycleStateDeleting
        - MachineLifecycleStateDeleteFailed
        - MachineLifecycleStateDeleted
    MachineConnectionState:
      type: string
      enum: [online, asleep, offline]
      x-enum-varnames:
        - MachineConnectionStateOnline
        - MachineConnectionStateAsleep
        - MachineConnectionStateOffline
    MachineAccessSourceKind:
      type: string
      enum: [org_role, project_machine_grant]
      x-enum-varnames:
        - MachineAccessSourceKindOrganizationRole
        - MachineAccessSourceKindProjectMachineGrant
    ProjectMachineGrantSourceKind:
      type: string
      enum: [explicit, pool]
      x-enum-varnames:
        - ProjectMachineGrantSourceKindExplicit
        - ProjectMachineGrantSourceKindPool
    Machine:
      type: object
      additionalProperties: false
      required: [id, org_id, source_kind, display_name, description, provider, lifecycle_state, connection_state, last_observed_at, cwd, env, secret_env, lifecycle_reason_code, lifecycle_reason_message, next_reconcile_after, provision_attempts, delete_attempts, metadata, deleted_at, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/MachineID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        source_kind:
          $ref: '#/components/schemas/MachineSourceKind'
        machine_pool_id:
          anyOf:
            - $ref: '#/components/schemas/MachinePoolID'
            - type: "null"
        display_name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        provider:
          type: string
        lifecycle_state:
          $ref: '#/components/schemas/MachineLifecycleState'
        connection_state:
          $ref: '#/components/schemas/MachineConnectionState'
        connection_state_reason:
          type: string
        last_observed_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        cwd:
          type: string
        env:
          type: object
          additionalProperties:
            type: string
        secret_env:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        lifecycle_reason_code:
          type: string
        lifecycle_reason_message:
          type: string
        failure_report:
          $ref: '#/components/schemas/MachineFailureReport'
        next_reconcile_after:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        provision_attempts:
          type: integer
          format: int32
        delete_attempts:
          type: integer
          format: int32
        metadata:
          $ref: '#/components/schemas/Metadata'
        deleted_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CreateMachineRequest:
      type: object
      additionalProperties: false
      required: [display_name]
      properties:
        display_name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        cwd:
          type: string
        env:
          type: object
          additionalProperties:
            type: string
        secret_env:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        metadata:
          $ref: '#/components/schemas/MachineMetadata'
    ConnectBYOMachineRequest:
      type: object
      additionalProperties: false
      required: [display_name]
      properties:
        display_name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        cwd:
          type: string
        env:
          type: object
          additionalProperties:
            type: string
        secret_env:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
        metadata:
          $ref: '#/components/schemas/MachineMetadata'
        project_ids:
          type: array
          maxItems: 100
          uniqueItems: true
          items:
            $ref: '#/components/schemas/ProjectID'
        token_name:
          $ref: '#/components/schemas/ResourceName'
          description: Optional daemon token name. Omitted values default to daemon.
    ConnectBYOMachineResponse:
      type: object
      additionalProperties: false
      required: [machine, token, token_record, project_grants]
      properties:
        machine:
          $ref: '#/components/schemas/Machine'
        token:
          type: string
          minLength: 1
          description: Opaque bearer credential.
        token_record:
          $ref: '#/components/schemas/MachineDaemonToken'
        project_grants:
          type: array
          items:
            $ref: '#/components/schemas/ProjectMachineGrant'
    UpdateMachineRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        cwd:
          type: string
        env:
          type: object
          additionalProperties:
            type: string
        secret_env:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SecretID'
    MachineSummaryFields:
      type: object
      description: Shared machine fields composed into machine response schemas. Composing schemas close their final shape with unevaluatedProperties.
      required: [id, org_id, source_kind, display_name, description, provider, lifecycle_state, connection_state, last_observed_at, deleted_at, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/MachineID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        source_kind:
          $ref: '#/components/schemas/MachineSourceKind'
        display_name:
          $ref: '#/components/schemas/ResourceName'
        description:
          type: string
        provider:
          type: string
        lifecycle_state:
          $ref: '#/components/schemas/MachineLifecycleState'
        connection_state:
          $ref: '#/components/schemas/MachineConnectionState'
        last_observed_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        deleted_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    MachineSummary:
      allOf:
        - $ref: '#/components/schemas/MachineSummaryFields'
      unevaluatedProperties: false
    MachineAccessSource:
      type: object
      additionalProperties: false
      required: [kind]
      properties:
        kind:
          $ref: '#/components/schemas/MachineAccessSourceKind'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        grant_id:
          $ref: '#/components/schemas/ProjectMachineGrantID'
        grant_source_kind:
          $ref: '#/components/schemas/ProjectMachineGrantSourceKind'
    MachineAccess:
      type: object
      additionalProperties: false
      required: [can_manage, sources]
      properties:
        can_manage:
          type: boolean
        sources:
          type: array
          items:
            $ref: '#/components/schemas/MachineAccessSource'
    VisibleMachine:
      allOf:
        - $ref: '#/components/schemas/MachineSummaryFields'
        - type: object
          required: [access]
          properties:
            access:
              $ref: '#/components/schemas/MachineAccess'
      unevaluatedProperties: false
    ListVisibleMachinesResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/VisibleMachine'
        next_cursor:
          type: [string, "null"]
    ProjectMachineGrant:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, machine_id, source_kind, description, metadata, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ProjectMachineGrantID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        machine_id:
          $ref: '#/components/schemas/MachineID'
        source_kind:
          $ref: '#/components/schemas/ProjectMachineGrantSourceKind'
        project_machine_pool_grant_id:
          anyOf:
            - $ref: '#/components/schemas/ProjectMachinePoolGrantID'
            - type: "null"
        description:
          type: string
        metadata:
          $ref: '#/components/schemas/Metadata'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CreateProjectMachineGrantRequest:
      type: object
      additionalProperties: false
      required: [machine_id]
      properties:
        machine_id:
          $ref: '#/components/schemas/MachineID'
        description:
          type: string
        metadata:
          $ref: '#/components/schemas/Metadata'
    CreateProjectMachineGrantResponse:
      type: object
      additionalProperties: false
      required: [grant, machine]
      properties:
        grant:
          $ref: '#/components/schemas/ProjectMachineGrant'
        machine:
          $ref: '#/components/schemas/Machine'
    ListProjectMachineGrantsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectMachineGrantListItem'
        next_cursor:
          type: [string, "null"]
    ProjectMachineGrantListItem:
      type: object
      additionalProperties: false
      required: [grant, machine]
      properties:
        grant:
          $ref: '#/components/schemas/ProjectMachineGrant'
        machine:
          $ref: '#/components/schemas/MachineSummary'
    ProjectMachinePoolGrant:
      type: object
      additionalProperties: false
      required: [id, org_id, project_id, machine_pool_id, description, default_machine_cpu, default_machine_memory_mb, default_machine_env_overlay, default_machine_secret_env_overlay, default_machine_provider_options_overlay, default_cwd, max_total_machines, max_total_cpu, max_total_memory_mb, min_machine_cpu, min_machine_memory_mb, max_machine_cpu, max_machine_memory_mb, delete_after_idle_minutes, metadata, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ProjectMachinePoolGrantID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        project_id:
          $ref: '#/components/schemas/ProjectID'
        machine_pool_id:
          $ref: '#/components/schemas/MachinePoolID'
        description:
          type: string
        default_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env_overlay:
          description: Env overlay merged over the pool's default_machine_env for machines materialized through this grant; a null entry removes the key.
          type: object
          additionalProperties:
            type: [string, "null"]
        default_machine_secret_env_overlay:
          description: Secret env overlay merged over the pool's default_machine_secret_env for machines materialized through this grant; a null entry removes the key.
          type: object
          additionalProperties:
            type: [string, "null"]
            pattern: '^sec_[a-z2-7]{26}$'
        default_machine_provider_options_overlay:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        max_total_machines:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine created through this grant. Zero disables deletion for this grant; null inherits the pool default.
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
          oneOf:
            - const: 0
            - type: integer
              minimum: 5
              maximum: 2147483647
            - type: "null"
        metadata:
          $ref: '#/components/schemas/Metadata'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CreateProjectMachinePoolGrantRequest:
      type: object
      additionalProperties: false
      required: [machine_pool_id]
      properties:
        machine_pool_id:
          $ref: '#/components/schemas/MachinePoolID'
        description:
          type: string
        default_machine_cpu:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env_overlay:
          description: Env overlay merged over the pool's default_machine_env for machines materialized through this grant; a null entry removes the key.
          type: object
          additionalProperties:
            type: [string, "null"]
        default_machine_secret_env_overlay:
          description: Secret env overlay merged over the pool's default_machine_secret_env for machines materialized through this grant; a null entry removes the key.
          type: object
          additionalProperties:
            type: [string, "null"]
            pattern: '^sec_[a-z2-7]{26}$'
        default_machine_provider_options_overlay:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        max_total_machines:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: integer
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine created through this grant. Use 0 to disable for this grant; omit to inherit the pool default. Values from 1 through 4 are invalid.
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
          oneOf:
            - const: 0
            - type: integer
              minimum: 5
              maximum: 2147483647
        metadata:
          $ref: '#/components/schemas/Metadata'
    UpdateProjectMachinePoolGrantRequest:
      type: object
      description: >-
        Update a project machine pool grant. Omitted fields keep their current values. Null clears
        an override so the grant follows the machine pool again. Overlay objects and metadata are
        replaced whole when present; send an empty object to clear them.
      additionalProperties: false
      minProperties: 1
      properties:
        description:
          type: string
        default_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        default_machine_env_overlay:
          type: object
          additionalProperties:
            type: [string, "null"]
        default_machine_secret_env_overlay:
          type: object
          additionalProperties:
            type: [string, "null"]
            pattern: '^sec_[a-z2-7]{26}$'
        default_machine_provider_options_overlay:
          type: object
          additionalProperties: true
        default_cwd:
          type: string
        max_total_machines:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_total_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        min_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
        max_machine_cpu:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        max_machine_memory_mb:
          type: [integer, "null"]
          format: int32
          minimum: 1
          maximum: 2147483647
        delete_after_idle_minutes:
          description: Idle minutes before deleting a machine created through this grant. Use 0 to disable for this grant; null restores inheritance from the pool; omitted leaves it unchanged. Values from 1 through 4 are invalid.
          type: [integer, "null"]
          format: int32
          minimum: 0
          maximum: 2147483647
          oneOf:
            - const: 0
            - type: integer
              minimum: 5
              maximum: 2147483647
            - type: "null"
        metadata:
          $ref: '#/components/schemas/Metadata'
    ListProjectMachinePoolGrantsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectMachinePoolGrantListItem'
        next_cursor:
          type: [string, "null"]
    ProjectMachinePoolGrantListItem:
      type: object
      additionalProperties: false
      required: [grant, machine_pool]
      properties:
        grant:
          $ref: '#/components/schemas/ProjectMachinePoolGrant'
        machine_pool:
          $ref: '#/components/schemas/MachinePoolSummary'
    MachinePoolSummary:
      type: object
      additionalProperties: false
      required: [id, org_id, name, management_kind, description, provider, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/MachinePoolID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        management_kind:
          $ref: '#/components/schemas/ManagementKind'
        description:
          type: string
        provider:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    CreateMachineDaemonTokenRequest:
      type: object
      additionalProperties: false
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
          description: Optional token name. Omitted values default to daemon.
        metadata:
          $ref: '#/components/schemas/Metadata'
    MachineDaemonToken:
      type: object
      additionalProperties: false
      required: [id, org_id, machine_id, name, metadata, created_at, last_used_at, revoked_at, revoke_reason]
      properties:
        id:
          $ref: '#/components/schemas/MachineDaemonTokenID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        machine_id:
          $ref: '#/components/schemas/MachineID'
        name:
          $ref: '#/components/schemas/ResourceName'
        metadata:
          $ref: '#/components/schemas/Metadata'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        last_used_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        revoked_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        revoke_reason:
          type: string
    CreateMachineDaemonTokenResponse:
      type: object
      additionalProperties: false
      required: [token, token_record]
      properties:
        token:
          type: string
          minLength: 1
          description: Opaque bearer credential.
        token_record:
          $ref: '#/components/schemas/MachineDaemonToken'
    ListMachineDaemonTokensResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MachineDaemonToken'
        next_cursor:
          type: [string, "null"]
    ProcessActionReconciliationClaim:
      type: object
      additionalProperties: false
      required: [process_action_id, seq, action_kind, position]
      properties:
        process_action_id:
          $ref: '#/components/schemas/ProcessActionID'
        seq:
          type: integer
          format: int64
          minimum: 1
        action_kind:
          type: string
          enum: [write, interrupt, terminate]
        position:
          type: string
          enum: [effect_committed, terminal]
    ProcessReconciliationClaim:
      type: object
      additionalProperties: false
      required:
        - process_id
        - supervisor_instance_id
        - phase
        - supervisor_live
        - execution_committed
        - action_admission_closed
        - resolved_action_seq
        - actions
      properties:
        process_id:
          $ref: '#/components/schemas/ProcessID'
        supervisor_instance_id:
          type: string
          minLength: 1
        phase:
          type: string
          enum: [preparing, prepared, accepted, terminal]
        supervisor_live:
          type: boolean
        execution_committed:
          type: boolean
        action_admission_closed:
          type: boolean
        resolved_action_seq:
          type: integer
          format: int64
          minimum: 0
        actions:
          type: array
          items:
            $ref: '#/components/schemas/ProcessActionReconciliationClaim'
    ProcessActionReconciliationDirective:
      type: object
      additionalProperties: false
      required: [process_action_id, seq, action_kind, disposition]
      properties:
        process_action_id:
          $ref: '#/components/schemas/ProcessActionID'
        seq:
          type: integer
          format: int64
          minimum: 1
        action_kind:
          type: string
          enum: [write, read, interrupt, terminate]
        disposition:
          type: string
          enum: [apply, retain, settle, release]
        payload: {}
    ProcessReconciliationDirective:
      type: object
      additionalProperties: false
      required: [process_id, supervisor_instance_id, disposition, actions]
      properties:
        process_id:
          $ref: '#/components/schemas/ProcessID'
        supervisor_instance_id:
          type: string
          minLength: 1
        disposition:
          type: string
          enum: [close_preparation, start, retain, release]
        actions:
          type: array
          items:
            $ref: '#/components/schemas/ProcessActionReconciliationDirective'
    RegisterDaemonRuntimeRequest:
      type: object
      additionalProperties: false
      required: [daemon_instance_id, daemon_version, processes]
      properties:
        daemon_instance_id:
          type: string
          format: uuid
        daemon_version:
          type: string
          minLength: 1
        capacity:
          type: object
          additionalProperties: true
        observed_platform:
          type: object
          additionalProperties: true
        processes:
          type: array
          items:
            $ref: '#/components/schemas/ProcessReconciliationClaim'
    DaemonRuntimeState:
      type: string
      enum: [active, ended]
      x-enum-varnames:
        - DaemonRuntimeStateActive
        - DaemonRuntimeStateEnded
    DaemonRuntime:
      type: object
      additionalProperties: false
      required: [id, org_id, machine_id, daemon_instance_id, daemon_version, state, state_reason_code, state_reason_message, created_at, last_seen_at, lease_expires_at, next_heartbeat_after_ms, ended_at, capacity]
      properties:
        id:
          $ref: '#/components/schemas/DaemonRuntimeID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        machine_id:
          $ref: '#/components/schemas/MachineID'
        daemon_instance_id:
          type: string
          format: uuid
        daemon_version:
          type: string
        state:
          $ref: '#/components/schemas/DaemonRuntimeState'
        state_reason_code:
          type: string
        state_reason_message:
          type: string
        created_at:
          $ref: '#/components/schemas/Timestamp'
        last_seen_at:
          $ref: '#/components/schemas/Timestamp'
        lease_expires_at:
          $ref: '#/components/schemas/Timestamp'
        next_heartbeat_after_ms:
          type: integer
          format: int64
        ended_at:
          anyOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: "null"
        capacity:
          type: object
          additionalProperties: true
    DaemonRuntimeReconciliation:
      type: object
      additionalProperties: false
      required: [processes]
      properties:
        processes:
          type: array
          items:
            $ref: '#/components/schemas/ProcessReconciliationDirective'
    RegisterDaemonRuntimeResponse:
      type: object
      additionalProperties: false
      required: [runtime, reconciliation]
      properties:
        runtime:
          $ref: '#/components/schemas/DaemonRuntime'
        reconciliation:
          $ref: '#/components/schemas/DaemonRuntimeReconciliation'
    BootstrapDaemonResponse:
      type: object
      additionalProperties: false
      required: [installation_id, machine_id]
      properties:
        installation_id:
          $ref: '#/components/schemas/InstallationID'
        machine_id:
          $ref: '#/components/schemas/MachineID'
    UploadArtifactResponse:
      type: object
      additionalProperties: false
      required: [artifact_id]
      properties:
        artifact_id:
          $ref: '#/components/schemas/ArtifactID'
    CreateProjectRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          $ref: '#/components/schemas/ResourceName'
    ProjectFields:
      type: object
      description: Shared project fields composed into project response schemas. Composing schemas close their final shape with unevaluatedProperties.
      required: [id, org_id, name, created_at, updated_at]
      properties:
        id:
          $ref: '#/components/schemas/ProjectID'
        org_id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
    Project:
      allOf:
        - $ref: '#/components/schemas/ProjectFields'
      unevaluatedProperties: false
    ProjectAccess:
      type: object
      additionalProperties: false
      required: [can_read, can_manage, can_manage_access, can_operate]
      properties:
        can_read:
          type: boolean
        can_manage:
          type: boolean
        can_manage_access:
          type: boolean
        can_operate:
          type: boolean
    VisibleProject:
      allOf:
        - $ref: '#/components/schemas/ProjectFields'
        - type: object
          required: [access]
          properties:
            access:
              $ref: '#/components/schemas/ProjectAccess'
      unevaluatedProperties: false
    ListProjectsResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/VisibleProject'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    OrgOverviewResponse:
      type: object
      additionalProperties: false
      required: [projects, recent_agents, recent_agent_profiles]
      properties:
        projects:
          type: array
          description: Projects visible to the caller, newest first (capped).
          items:
            $ref: '#/components/schemas/VisibleProject'
        recent_agents:
          type: array
          description: >-
            Most recently active agents across the caller's readable projects,
            ordered by updated_at descending.
          items:
            $ref: '#/components/schemas/Agent'
        recent_agent_profiles:
          type: array
          description: >-
            Most recently updated agent profiles across the caller's readable
            projects, ordered by updated_at descending.
          items:
            $ref: '#/components/schemas/AgentProfile'
    CurrentUserIdentity:
      type: object
      additionalProperties: false
      required: [id, email, display_name]
      properties:
        id:
          $ref: '#/components/schemas/UserID'
        email:
          type: string
          description: The user's primary verified email, or an empty string if none.
        display_name:
          type: string
    CurrentUserOrg:
      type: object
      additionalProperties: false
      required: [id, name, role, created_at]
      properties:
        id:
          $ref: '#/components/schemas/OrganizationID'
        name:
          $ref: '#/components/schemas/ResourceName'
        role:
          type: string
          description: The authenticated user's role in this organization.
        created_at:
          allOf:
            - $ref: '#/components/schemas/Timestamp'
          description: Organization creation timestamp, not the membership join timestamp.
    CurrentUser:
      type: object
      additionalProperties: false
      required: [user, orgs]
      properties:
        user:
          $ref: '#/components/schemas/CurrentUserIdentity'
        orgs:
          type: array
          items:
            $ref: '#/components/schemas/CurrentUserOrg'
    ListPersonalAccessTokensResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/PersonalAccessToken'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    OrgMember:
      type: object
      additionalProperties: false
      required: [user_id, email, display_name, role, created_at]
      properties:
        user_id:
          $ref: '#/components/schemas/UserID'
        email:
          type: string
          description: The member's primary verified email, or an empty string if none.
        display_name:
          type: string
        role:
          type: string
          description: The member's role in the organization (owner, admin, or member).
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ListOrgMembersResponse:
      type: object
      additionalProperties: false
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/OrgMember'
        next_cursor:
          type: [string, "null"]
          description: Opaque cursor for the next page, or null when this is the last page.
    UpdateOrgMemberRequest:
      type: object
      additionalProperties: false
      required: [role]
      properties:
        role:
          type: string
          description: The member's new org role (admin or member).
    SetProjectMembershipRequest:
      type: object
      additionalProperties: false
      required: [role]
      properties:
        role:
          type: string
          description: The member's project role (admin, developer, operator, or viewer).
    ProjectMembershipGrant:
      type: object
      additionalProperties: false
      required: [project_id, project_name, role, created_at]
      properties:
        project_id:
          $ref: '#/components/schemas/ProjectID'
        project_name:
          $ref: '#/components/schemas/ResourceName'
        role:
          type: string
          description: The member's role on the project (admin, developer, operator, or viewer).
        created_at:
          $ref: '#/components/schemas/Timestamp'
    ListProjectMembershipGrantsResponse:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ProjectMembershipGrant'
