openapi: 3.0.0
info:
    title: Enaibleu Sovereinty API
    description: API for Enaibleu Sovereinty Security Core.
    version: 11.0.0
servers:
  - url: https://{domain}
    description: Production Server
paths:
  # System Endpoints
  /enaibleusovereignty/api/v1/health:
    get:
      summary: System Health
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/status:
    get:
      summary: System Status
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/version:
    get:
      summary: Protocol Version
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/manifest:
    get:
      summary: Get Manifest
      description: Get the Protocol Manifest markdown
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/openapi.yaml:
    get:
      summary: Get OpenAPI Spec
      description: Public read-only OpenAPI contract for the live Enaibleu Sovereinty API.
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/tools/catalog:
    get:
      summary: List authenticated tool catalog entries
      description: Admin session required. Returns structured tool metadata for the dashboard tool console and authenticated runtime tooling.
      security:
        - cookieAuth: []
      parameters:
        - name: category
          in: query
          required: false
          schema: {type: string}
        - name: tool_name
          in: query
          required: false
          schema: {type: string}
      responses:
        '200':
          description: Tool catalog
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  tools:
                    type: array
                    items:
                      type: object
                      properties:
                        name: {type: string}
                        category: {type: string}
                        description: {type: string}
                        params:
                          type: array
                          items: {type: string}
                        examples:
                          type: array
                          items: {type: string}
                  error: {type: string}
  /enaibleusovereignty/api/v1/tools/execute:
    post:
      summary: Execute an authenticated dashboard tool
      description: |
        Admin session required. Executes any governed MCP tool through the dashboard tool console surface.

        **Available tools (new in this release):**
        - `mcp_nexus_docs_index` — Fetch and index a library doc URL into agent_research (source=library-docs)
        - `mcp_nexus_docs_resolve` — List all indexed docs for a library (e.g. `{"library":"nextjs"}`)
        - `mcp_nexus_docs_query` — Read doc content by exact slug (e.g. `{"slug":"docs-nextjs-app-router"}`)
        - `mcp_sentinel_validate_url` — HTTP HEAD check; returns alive, status_code, latency_ms, redirect_chain
        - `mcp_spectre_credibility_score` — Domain credibility scorer (0.0–1.0, HIGH/MEDIUM/LOW/SUSPICIOUS)
        - `mcp_sentinel_webhook` — POST/PUT/PATCH JSON to any webhook URL with custom headers
        - `mcp_nexus_research_tag` — Tag a file/URL/note/agent_research entry to a named research session
        - `mcp_nexus_research_session` — Read the full manifest for a research session
        - `mcp_nexus_synthesize` — Curator assembly engine: validates URLs, scores credibility, loads content, returns synthesis_context for LLM prose-writing
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [tool]
              properties:
                tool:
                  type: string
                  description: Tool name (e.g. mcp_nexus_synthesize)
                  example: mcp_nexus_synthesize
                params:
                  type: object
                  additionalProperties: true
                  description: Tool-specific parameters
                  example:
                    research_id: defi-landscape-2026
                    output_format: report
                    title: DeFi Landscape 2026
                    validate_urls: true
                    score_credibility: true
            examples:
              synthesize:
                summary: Run Curator synthesis on a research session
                value:
                  tool: mcp_nexus_synthesize
                  params:
                    research_id: defi-landscape-2026
                    output_format: report
                    title: DeFi Landscape 2026
              tag_research:
                summary: Tag a URL to a research session
                value:
                  tool: mcp_nexus_research_tag
                  params:
                    research_id: defi-landscape-2026
                    type: url
                    path: https://arxiv.org/abs/2401.00001
                    agent: librarian
                    note: Key paper on MEV
              validate_url:
                summary: Validate a URL
                value:
                  tool: mcp_sentinel_validate_url
                  params:
                    url: https://arxiv.org/abs/2401.00001
              credibility_score:
                summary: Score domain credibility
                value:
                  tool: mcp_spectre_credibility_score
                  params:
                    url: https://arxiv.org/abs/2401.00001
              webhook:
                summary: Send webhook notification
                value:
                  tool: mcp_sentinel_webhook
                  params:
                    url: https://hooks.example.com/notify
                    payload:
                      event: report_ready
                      id: abc123
      responses:
        '200':
          description: Tool execution result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  tool: {type: string}
                  content: {type: string}
                  error: {type: string}
  /enaibleusovereignty/api/v1/documentation/audit:
    get:
      summary: Audit dashboard documentation coverage
      description: Authenticated route-to-doc audit for the markdown-backed Documentation control plane. Returns coverage, missing route sections, and orphaned doc sections by category.
      security:
        - cookieAuth: []
      parameters:
        - name: category
          in: query
          required: false
          schema: {type: string, enum: [spectre, nexus, sentinel, workbench, agents]}
          description: Optional category filter for a single documentation lane.
      responses:
        '200':
          description: Documentation audit report
  /enaibleusovereignty/api/v1/documentation/sync:
    post:
      summary: Synchronize missing dashboard documentation sections
      description: Admin-only deterministic sync that appends missing route sections into the markdown-backed Documentation control plane.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum: [spectre, nexus, sentinel, workbench, agents]
                  description: Optional category filter. When omitted, sync runs across all documentation lanes.
      responses:
        '200':
          description: Documentation sync report
  /enaibleusovereignty/api/v1/documentation/audit/run:
    post:
      summary: Run and persist a documentation audit report
      description: Admin-only documentation audit execution that persists a governed Nexus report, writes a markdown artifact, and can create Documenter drift tasks.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum: [spectre, nexus, sentinel, workbench, agents]
                auto_sync:
                  type: boolean
                create_drift_tasks:
                  type: boolean
                queue_ai_enrichment_task:
                  type: boolean
      responses:
        '200':
          description: Persisted documentation audit report
  /enaibleusovereignty/api/v1/documentation/screenshots/refresh:
    post:
      summary: Refresh authenticated documentation screenshots
      description: Admin-only refresh that captures current dashboard route screenshots with the caller's authenticated session and persists them through the governed screenshot lane for later Documenter use.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum: [spectre, nexus, sentinel, workbench, agents]
                  description: Optional category filter. When omitted, refresh runs across all documentation lanes.
      responses:
        '200':
          description: Documentation screenshot refresh report
  /enaibleusovereignty/api/v1/documentation/enrich:
    post:
      summary: Queue Documenter enrichment tasks
      description: Admin-only queue for Documenter enrichment tasks that turn deterministic documentation baselines into richer operator docs after drift review.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum: [spectre, nexus, sentinel, workbench, agents]
      responses:
        '200':
          description: Documentation enrichment task queue report
  /enaibleusovereignty/api/v1/documentation/enrich/run:
    post:
      summary: Run Documenter AI enrichment
      description: Admin-only Documenter rewrite pass that can refresh authenticated dashboard screenshots, upgrades markdown docs after deterministic sync, validates route coverage, and persists a fresh documentation report.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum: [spectre, nexus, sentinel, workbench, agents]
                auto_sync:
                  type: boolean
                refresh_screenshots:
                  type: boolean
      responses:
        '200':
          description: AI enrichment run report
  /enaibleusovereignty/api/v1/system/logs/stream:
    get:
      summary: Stream System Logs (SSE)
      description: Admin session required. Streams recent request logs over SSE.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Server-Sent Events stream

  # Authentication Endpoints
  /enaibleusovereignty/api/v1/auth/login:
    post:
      summary: Login
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email: {type: string}
                password: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/auth/register:
    post:
      summary: Register
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email: {type: string}
                password: {type: string}
                passwordConfirm: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/auth/logout:
    post:
      summary: Logout
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/auth/me:
    get:
      summary: Get Current User
      responses:
        '200':
          description: OK

  # API Key Management
  /enaibleusovereignty/api/v1/keys:
    get:
      summary: List API Keys
      description: List API keys for the authenticated user. Admins may optionally specify a different owner.
      security:
        - cookieAuth: []
      parameters:
        - name: owner
          in: query
          required: false
          schema: {type: string}
          description: Optional user ID. Admin-only when listing keys for another user.
      responses:
        '200':
          description: OK
    post:
      summary: Generate API Key
      description: Creates a new API key. Owner can be "current" to use the authenticated user's ID.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name: {type: string, description: Name for the API key (3-100 chars)}
                owner: {type: string, description: User ID or "current" for authenticated user}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/keys/{id}:
    delete:
      summary: Revoke API Key
      description: Revoke an API key owned by the authenticated user. Admins may revoke any key.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/keys/my-key:
    get:
      summary: Get My API Key Status
      description: Returns the current user's API key status (requires session auth)
      security:
        - cookieAuth: []
      responses:
        '200':
          description: API key status
          content:
            application/json:
              schema:
                type: object
                properties:
                  has_key: {type: boolean}
                  totalKeys: {type: integer}
                  key:
                    type: object
                    properties:
                      id: {type: string}
                      name: {type: string}
                      created: {type: string}
                      last_used: {type: string}
                      is_revoked: {type: boolean}
                  message: {type: string}

  # OIN Register
  /enaibleusovereignty/api/v1/oin:
    get:
      summary: Search OIN
      parameters:
        - name: q
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/oin/sync:
    post:
      summary: Trigger OIN Sync
      responses:
        '202':
          description: Accepted

  # RBAC
  /enaibleusovereignty/api/v1/rbac/matrix:
    get:
      summary: Get RBAC Matrix
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/rbac/update:
    post:
      summary: Update Role Permissions
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                role: {type: string}
                permissions: {type: array, items: {type: string}}
      responses:
        '200':
          description: OK

  # Admin Identity
  /enaibleusovereignty/api/v1/admin/users:
    get:
      summary: List Users
      description: Admin session required. Returns paginated users with optional PocketBase expand parameters such as `expand=role`.
      security:
        - cookieAuth: []
      parameters:
        - name: page
          in: query
          required: false
          schema: {type: integer}
        - name: perPage
          in: query
          required: false
          schema: {type: integer}
        - name: expand
          in: query
          required: false
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/roles:
    get:
      summary: List Roles
      description: Admin session required. Returns paginated protocol roles.
      security:
        - cookieAuth: []
      parameters:
        - name: page
          in: query
          required: false
          schema: {type: integer}
        - name: perPage
          in: query
          required: false
          schema: {type: integer}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/roles/{id}:
    get:
      summary: Get Role
      description: Admin session required. Fetch a single protocol role by record ID.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
    delete:
      summary: Delete Role
      description: Admin session required. Delete a protocol role by record ID.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK

  /enaibleusovereignty/api/v1/feedback:
    post:
      summary: Submit Feedback
      description: Public contact-form submission endpoint.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [from_name, from_email, message]
              properties:
                from_name: {type: string}
                from_email: {type: string}
                subject: {type: string}
                message: {type: string}
                status: {type: string, description: Optional; defaults to new}
      responses:
        '201':
          description: Created
  /enaibleusovereignty/api/v1/admin/feedback:
    get:
      summary: List Feedback
      description: Admin session required. Returns feedback submissions ordered by `sort` when provided.
      security:
        - cookieAuth: []
      parameters:
        - name: sort
          in: query
          required: false
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/feedback/{id}:
    patch:
      summary: Update Feedback
      description: Admin session required. Currently used for status updates.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: {type: string, enum: [new, read, resolved]}
      responses:
        '200':
          description: OK
    delete:
      summary: Delete Feedback
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK

  # Security
  /enaibleusovereignty/api/v1/security/blacklist:
    get:
      summary: Get Security Blacklist
      description: Admin session required. Returns banned IPs with geo location data.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: List of blacklist entries
  /enaibleusovereignty/api/v1/security/ban:
    post:
      summary: Ban an IP Address
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                ip: {type: string, description: IP address to ban}
                reason: {type: string, description: Reason for the ban}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/security/unban/{id}:
    delete:
      summary: Unban an IP Address
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/security/stats:
    get:
      summary: Get Security Statistics
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/security/enrich-geo:
    post:
      summary: Enrich Blacklist with Geo Location Data
      description: Looks up geo location for all blacklist entries that don't have it
      responses:
        '200':
          description: Object with enriched, skipped, and failed counts

  # Security Tools — Autonomous Spectre/Sentinel Scanners
  /enaibleusovereignty/api/v1/security/tools/results:
    get:
      summary: Get Latest Security Tool Results
      description: Returns the most-recent ToolResult for every tool as a map keyed by tool ID.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Map of toolID → ToolResult
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/ssl-monitor:
    post:
      summary: Run SSL Certificate Monitor (Spectre)
      description: Checks TLS certificate expiry for all MONITORED_DOMAINS. Warns at <30 days, critical at <7 days.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with report_id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/dependency-scan:
    post:
      summary: Run Dependency Vulnerability Scanner (Spectre)
      description: Scans Go + npm dependencies for CVEs via OSV.dev free API.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with CVE findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/owasp-scan:
    post:
      summary: Run OWASP API Scanner (Spectre)
      description: Checks own API for OWASP Top 10 issues — headers, CORS, auth enforcement, rate limiting.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with OWASP findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/github-secrets:
    post:
      summary: Run GitHub Secrets Scanner (Spectre)
      description: Searches GitHub Code Search for exposed API keys and env vars. Requires GITHUB_TOKEN env var.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with exposed secret findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/brute-force-scan:
    post:
      summary: Run Brute Force Sentinel (Sentinel)
      description: Scans audit log for repeated failed auth; auto-bans IPs with ≥5 failures in 15 min.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with banned/suspicious IPs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/session-anomaly:
    post:
      summary: Run Session Anomaly Detector (Sentinel)
      description: Flags accounts active from 3+ distinct /16 subnets within 24 hours.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with anomalous account findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/web-reputation:
    post:
      summary: Run Web Reputation Monitor (Sentinel)
      description: Checks server IP(s) against AbuseIPDB. Requires ABUSEIPDB_API_KEY env var.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with reputation findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  /enaibleusovereignty/api/v1/security/tools/dark-web-breach:
    post:
      summary: Run Dark Web Breach Monitor (Sentinel)
      description: Checks domain email accounts against HaveIBeenPwned v3. Requires HIBP_API_KEY env var.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: ToolResult with breach findings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolResult'

  # Spectre (Web Intelligence)
  /enaibleusovereignty/api/v1/spectre/scout:
    post:
      summary: Sovereign Web Search
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                query: {type: string}
                thinking: {type: boolean}
                no_cache: {type: boolean}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/health:
    post:
      summary: Link Health Scanner
      description: High-performance scanner for dead-link discovery and SEO arbitrage. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                target_domain: {type: string, description: The domain to scan for broken outbound links}
                depth: {type: integer, description: Recursion depth (e.g. 1)}
                min_dr: {type: integer, description: Minimum Domain Rating filter}
      responses:
        '200':
          description: Link Health Report with broken links and expired domain signals
  /enaibleusovereignty/api/v1/spectre/crawl:
    post:
      summary: Start Security Crawl
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/targets:
    get:
      summary: List Spectre Targets
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/snapshot:
    get:
      summary: Get Spectre Snapshot
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: url
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/intelligence:
    get:
      summary: Get Intelligence Data
      description: Returns highly detailed semantic data (emails, socials, tech stack, h1) harvested from websites. Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: target_id
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id: {type: string}
                    url: {type: string}
                    title: {type: string}
                    description: {type: string}
                    h1: {type: string}
                    keywords: {type: string}
                    emails: {type: array, items: {type: string}}
                    social_links: {type: array, items: {type: string}}
                    tech_stack: {type: array, items: {type: string}}
                    word_count: {type: integer}
  /enaibleusovereignty/api/v1/spectre/fetch:
    post:
      summary: Fetch URL as Markdown
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url: {type: string}
                no_cache: {type: boolean}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/recent:
    get:
      summary: List Recent Fetches
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/synthesis:
    post:
      summary: Synthesize Content
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                topic: {type: string}
                sources: {type: array, items: {type: string}}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/discord/dm:
    post:
      summary: Send Discord DM
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                user_id: {type: string}
                content: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/discord/channel:
    post:
      summary: Send Discord Channel Message
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                channel_id: {type: string}
                content: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/extract:
    post:
      summary: Extract Structured Data from URL
      description: Extract structured data using CSS selectors (similar to Firecrawl). Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url: {type: string, description: Target URL to extract from}
                selector: {type: string, description: CSS selector for elements}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/sitemap:
    post:
      summary: Parse Sitemap
      description: Parse sitemap.xml to extract all URLs. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url: {type: string, description: Target URL to fetch sitemap from}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/robots:
    post:
      summary: Parse Robots.txt
      description: Parse robots.txt to extract crawl rules. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url: {type: string, description: Target URL to fetch robots.txt from}
      responses:
        '200':
          description: OK

  # Academy
  /enaibleusovereignty/api/v1/academy/report:
    post:
      summary: Report XP/Activity
      description: Requires authenticated session or system API key.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                user_id: {type: string}
                activity: {type: string}
                xp: {type: integer}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/academy/stats:
    get:
      summary: Get Academy Stats
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/academy/roles:
    get:
      summary: Get Academy Roles
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/academy/logs:
    get:
      summary: List Academy Logs
      description: Session required. Returns filtered academy audit logs.
      security:
        - cookieAuth: []
      parameters:
        - name: page
          in: query
          schema: {type: integer}
        - name: perPage
          in: query
          schema: {type: integer}
        - name: sort
          in: query
          schema: {type: string}
        - name: filter
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK

  # Agent Content
  /enaibleusovereignty/api/v1/agent/flows:
    get:
      summary: List Agent Flows
      description: Returns all registered agent flows.
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/flows/{id}:
    get:
      summary: Get Agent Flow
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/skills:
    get:
      summary: List Agent Skills
      description: Returns all registered agent skills.
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/skills/{id}:
    get:
      summary: Get Agent Skill
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/laws:
    get:
      summary: List Agent Laws
      description: Returns all registered agent laws.
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/laws/{id}:
    get:
      summary: Get Agent Law
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/jobs:
    get:
      summary: List Agent Jobs
      description: Admin session required. Returns autonomous jobs.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
    post:
      summary: Create Agent Job
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [slug, display_name, schedule]
              properties:
                slug: {type: string}
                display_name: {type: string}
                description: {type: string}
                schedule: {type: string}
                owner: {}
                executor_role: {type: string}
                flow: {type: string}
                execution_mode: {type: string}
                automation_unit: {type: string}
                parameters: {}
                status: {type: string}
                last_run: {type: string}
                next_run: {type: string}
                last_output: {type: string}
      responses:
        '201':
          description: Created
  /enaibleusovereignty/api/v1/agent/jobs/{id}:
    get:
      summary: Get Agent Job
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
    patch:
      summary: Update Agent Job
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                slug: {type: string}
                display_name: {type: string}
                description: {type: string}
                schedule: {type: string}
                owner: {}
                executor_role: {type: string}
                flow: {type: string}
                execution_mode: {type: string}
                automation_unit: {type: string}
                parameters: {}
                status: {type: string}
                last_run: {type: string}
                next_run: {type: string}
                last_output: {type: string}
      responses:
        '200':
          description: OK
    delete:
      summary: Delete Agent Job
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/templates:
    get:
      summary: List Agent Templates
      description: Returns all registered agent templates.
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/agent/templates/{id}:
    get:
      summary: Get Agent Template
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK

  # Librarian
  /enaibleusovereignty/api/v1/librarian/logs:
    get:
      summary: Get Research Logs
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/logs/stream:
    get:
      summary: Stream Research Logs (SSE)
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Server-Sent Events stream
  /enaibleusovereignty/api/v1/research/logs:
    get:
      summary: List Research Logs
      description: Session required. Returns filtered research logs.
      security:
        - cookieAuth: []
      parameters:
        - name: page
          in: query
          schema: {type: integer}
        - name: perPage
          in: query
          schema: {type: integer}
        - name: sort
          in: query
          schema: {type: string}
        - name: filter
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/research/logs/stream:
    get:
      summary: Stream Research Logs (SSE)
      description: Session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Server-Sent Events stream
  /enaibleusovereignty/api/v1/librarian/gaps:
    get:
      summary: Get Knowledge Gaps
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/tasks:
    post:
      summary: Create Task
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title: {type: string}
                content: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/tasks/detailed:
    post:
      summary: Create Detailed Task
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title: {type: string}
                description: {type: string}
                priority: {type: string}
                tags: {type: array, items: {type: string}}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/tasks/upload:
    post:
      summary: Upload Task File
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/research:
    get:
      summary: List Research
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/research/topic:
    get:
      summary: Get Research by Topic
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: topic
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/librarian/cleanup-titles:
    post:
      summary: Cleanup Research Titles
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK

  # Spectre Admin Data
  /enaibleusovereignty/api/v1/spectre/assets/{id}:
    patch:
      summary: Update Spectre Asset
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK
    delete:
      summary: Delete Spectre Asset
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/health/exclusions/{id}:
    delete:
      summary: Delete Spectre Exclusion
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/broken-links:
    get:
      summary: List Broken Links
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: sort
          in: query
          schema: {type: string}
        - name: filter
          in: query
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/broken-links/{id}:
    patch:
      summary: Update Broken Link
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/spectre/restorations:
    post:
      summary: Create Spectre Restoration
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK

  # Memory System Endpoints
  /enaibleusovereignty/api/v1/memory/save:
    post:
      summary: Save Memory
      description: Save a memory with automatic keyword extraction and deduplication
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content: {type: string}
                type: {type: string}
                keywords: {type: array, items: {type: string}}
                scope: {type: string, enum: [private, global]}
      responses:
        '200':
          description: OK

  /enaibleusovereignty/api/v1/memory/search:
    post:
      summary: Search Memories
      description: Search memories with fuzzy keyword matching
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query: {type: string}
                scope: {type: string, enum: [mine, global, all]}
                limit: {type: number}
      responses:
        '200':
          description: OK

  /enaibleusovereignty/api/v1/memory/{id}:
    delete:
      summary: Delete Memory
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK

  /enaibleusovereignty/api/v1/nexus/traces:
    get:
      summary: List LLM Traces
      description: List LLM and Spectre traces with enrichment labels
      security:
        - cookieAuth: []
      responses:
        '200':
          description: OK

  /enaibleusovereignty/api/v1/nexus/traces/{filename}:
    get:
      summary: Get Trace Detail
      security:
        - cookieAuth: []
      parameters:
        - name: filename
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK

  # Chat System
  /enaibleusovereignty/api/v1/chat/sessions:
    get:
      summary: List Chat Sessions
      responses:
        '200':
          description: List of chat sessions
    post:
      summary: Create Chat Session
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title: {type: string}
      responses:
        '201':
          description: Session created
  /enaibleusovereignty/api/v1/chat/sessions/{id}:
    get:
      summary: Get Chat Session
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Session details
    delete:
      summary: Archive Chat Session
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Session archived
  /enaibleusovereignty/api/v1/chat/sessions/{id}/messages:
    get:
      summary: Get Session Messages
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: List of messages
    post:
      summary: Send Message to Session
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                content: {type: string}
                attachments: {type: array, items: {type: string}}
                agent_persona: {type: string}
      responses:
        '200':
          description: Message response
  /enaibleusovereignty/api/v1/chat/messages:
    post:
      summary: Send Message (Auto-create Session)
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                content: {type: string}
                session_id: {type: string}
                attachments: {type: array, items: {type: string}}
                agent_persona: {type: string}
      responses:
        '200':
          description: Message response
  /enaibleusovereignty/api/v1/chat/search:
    get:
      summary: Search Chat History
      parameters:
        - name: q
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Search results
  /enaibleusovereignty/api/v1/chat/usage:
    get:
      summary: Get Chat Usage Stats
      responses:
        '200':
          description: Usage statistics

  # Mail
  /enaibleusovereignty/api/v1/mail/send:
    post:
      summary: Send Email
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                account_email: {type: string}
                message:
                  type: object
                  properties:
                    from: {type: string}
                    to: {type: array, items: {type: string}}
                    subject: {type: string}
                    body: {type: string}
                    encrypt_body: {type: boolean}
      responses:
        '202':
          description: Accepted
  /enaibleusovereignty/api/v1/mail/accounts:
    get:
      summary: List Mail Accounts
      description: Admin session required. Use `active=true` to list only active accounts.
      security:
        - cookieAuth: []
      parameters:
        - name: active
          in: query
          required: false
          schema: {type: boolean}
      responses:
        '200':
          description: OK
    post:
      summary: Create Mail Account
      description: Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [name, email, host, port, username, password]
              properties:
                name: {type: string}
                email: {type: string}
                host: {type: string}
                port: {type: integer}
                username: {type: string}
                password: {type: string}
                active: {type: boolean}
                insecure: {type: boolean}
      responses:
        '201':
          description: Created
  /enaibleusovereignty/api/v1/mail/accounts/{id}:
    patch:
      summary: Update Mail Account
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name: {type: string}
                email: {type: string}
                host: {type: string}
                port: {type: integer}
                username: {type: string}
                password: {type: string}
                active: {type: boolean}
                insecure: {type: boolean}
      responses:
        '200':
          description: OK
    delete:
      summary: Delete Mail Account
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/mail/tls-health:
    get:
      summary: TLS Health Check
      responses:
        '200':
          description: TLS status

  # License
  /enaibleusovereignty/api/v1/license/verify:
    post:
      summary: Verify License
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                license_key: {type: string}
      responses:
        '200':
          description: License verification result
  /enaibleusovereignty/api/v1/license/activate:
    post:
      summary: Activate License
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                license_key: {type: string}
                user_id: {type: string}
      responses:
        '200':
          description: License activated
  /enaibleusovereignty/api/v1/license/check/{id}:
    get:
      summary: Check License Status
      description: Returns generic invalid state for unknown install IDs to reduce enumeration.
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: License status
  /enaibleusovereignty/api/v1/downloads/track:
    post:
      summary: Track Download
      description: Tracks a download event. Client-supplied IP addresses are ignored.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                version: {type: string}
                install_id: {type: string}
                email: {type: string}
                source: {type: string}
                referrer: {type: string}
                user_agent: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/downloads/stats:
    get:
      summary: Get Download Stats
      description: Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Download statistics

  # Features
  /enaibleusovereignty/api/v1/features:
    get:
      summary: Get All Features
      responses:
        '200':
          description: List of features
  /enaibleusovereignty/api/v1/features/matrix:
    get:
      summary: Get Feature Matrix
      responses:
        '200':
          description: Feature matrix by tier
  /enaibleusovereignty/api/v1/features/plans:
    get:
      summary: Get Pricing Plans
      responses:
        '200':
          description: Available plans
  /enaibleusovereignty/api/v1/features/check:
    get:
      summary: Check Feature Access
      parameters:
        - name: feature
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Access check result

  # Sentinel MCP Functions
  /enaibleusovereignty/api/v1/sentinel/query:
    post:
      summary: Query Database Collection
      description: Admin session required. Query a restricted allowlist of Sentinel collections.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                collection:
                  type: string
                  description: Allowed values include agent_skills, agent_templates, agent_flows, agent_jobs, agent_roles, agent_research, users
                filter:
                  type: string
                  description: Validated PocketBase filter expression
                limit:
                  type: integer
                  description: Maximum records to return (1-100)
      responses:
        '200':
          description: Query results
  /enaibleusovereignty/api/v1/sentinel/skills:
    get:
      summary: List Agent Skills
      description: List all available agent skills
      responses:
        '200':
          description: List of agent skills
  /enaibleusovereignty/api/v1/sentinel/templates:
    get:
      summary: List Agent Templates
      description: List all available agent templates
      responses:
        '200':
          description: List of agent templates
  /enaibleusovereignty/api/v1/sentinel/flows:
    get:
      summary: List Agent Flows
      description: List all available agent flows
      responses:
        '200':
          description: List of agent flows
  /enaibleusovereignty/api/v1/sentinel/spawn:
    post:
      summary: Spawn Agent
      description: Create a new agent from a template
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                template:
                  type: string
                  description: The template slug to spawn from
                name:
                  type: string
                  description: Name for the new agent
                task:
                  type: string
                  description: Task/mission for the agent
      responses:
        '200':
          description: Agent spawned successfully

  # News & Intel Pipeline
  /enaibleusovereignty/api/v1/news:
    get:
      summary: List Published Dispatches
      parameters:
        - name: archive
          in: query
          schema: {type: boolean}
          description: Filter for archived dispatches
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/news/{slug}:
    get:
      summary: Get Dispatch by Slug
      parameters:
        - name: slug
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/news/generate:
    post:
      summary: Generate Intel Dispatch
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                topic: {type: string}
                keywords: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/news/dispatches:
    get:
      summary: List News Dispatches
      description: Admin session required. Returns draft and published dispatches with optional sort and filter.
      security:
        - cookieAuth: []
      parameters:
        - name: sort
          in: query
          required: false
          schema: {type: string}
        - name: filter
          in: query
          required: false
          schema: {type: string}
      responses:
        '200':
          description: OK
  /enaibleusovereignty/api/v1/admin/news/dispatches/{id}:
    patch:
      summary: Update News Dispatch
      description: Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: {type: string}
                published_at: {type: string}
      responses:
        '200':
          description: OK

  # Hunter — News harvest + Seedlist management
  /enaibleusovereignty/api/v1/spectre/cve/run:
    post:
      summary: Spectre — Run CVE Intelligence Harvest
      description: Crawls security sources (NVD, CISA KEV, BleepingComputer, The Hacker News, Dark Reading, MSRC, GitHub Security, SecurityWeek), extracts CVE IDs, classifies by CVSS severity, synthesises an AI security briefing, and publishes a hunter_cve Nexus report. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                seedlist_id:
                  type: string
                  description: Optional PocketBase record ID of a custom CVE seedlist. Leave empty to auto-select or use built-in defaults.
      responses:
        '200':
          description: CVE harvest result
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      cves_found:     {type: integer}
                      cves_critical:  {type: integer}
                      cves_high:      {type: integer}
                      cves_medium:    {type: integer}
                      cves_low:       {type: integer}
                      seedlist_used:  {type: string}
                      seedlist_id:    {type: string}
                      report_id:      {type: string}
                      entries:
                        type: array
                        items:
                          type: object
                          properties:
                            id:          {type: string}
                            title:       {type: string}
                            description: {type: string}
                            severity:    {type: string}
                            cvss:        {type: number}
                            source_url:  {type: string}
                            domain:      {type: string}
  /enaibleusovereignty/api/v1/hunter/news/run:
    post:
      summary: Hunter — Run Daily News Harvest
      description: Triggers the Hunter agent to crawl AI news sources, synthesise a digest, and publish a dispatch. Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Harvest result with sources and dispatch ID
  /enaibleusovereignty/api/v1/hunter/seedlists:
    get:
      summary: Hunter — List Seedlists
      description: Returns all configured seedlists. Session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Array of seedlist objects
    post:
      summary: Hunter — Create Seedlist
      description: Creates a new seedlist. Session required.
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, seeds, keywords]
              properties:
                name:        {type: string}
                description: {type: string}
                category:    {type: string}
                seeds:
                  type: array
                  items: {type: string}
                keywords:
                  type: array
                  items: {type: string}
                hop_depth:   {type: integer}
                active:      {type: boolean}
                tags:
                  type: array
                  items: {type: string}
                exclude_patterns:
                  type: array
                  items: {type: string}
      responses:
        '200':
          description: Created seedlist
  /enaibleusovereignty/api/v1/hunter/seedlists/sync-from-hopper:
    post:
      summary: Hunter — Sync Seedlist From Hopper
      description: Promotes discovered hopper domains into a named seedlist. Session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Sync result
  /enaibleusovereignty/api/v1/hunter/seedlists/{id}:
    get:
      summary: Hunter — Get Seedlist
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Seedlist detail
    put:
      summary: Hunter — Update Seedlist
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated seedlist
    delete:
      summary: Hunter — Delete Seedlist
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Deleted

  # Spectre Extract
  /enaibleusovereignty/api/v1/spectre/extract/stream:
    post:
      summary: Spectre Extract — Stream Site Extraction
      description: Crawl a website and extract structured content (title, headings, markdown, links) per page. Returns SSE stream with progress events. Like Firecrawl/Tavily but sovereign. Admin session or API key required.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  description: Root URL to extract from
                max_depth:
                  type: integer
                  default: 3
                  description: Maximum crawl depth
                max_pages:
                  type: integer
                  default: 50
                  description: Maximum pages to extract
                hop_external:
                  type: boolean
                  default: false
                  description: Add discovered external domains to Spectre Hopper
                formats:
                  type: array
                  items:
                    type: string
                    enum: [json, md]
                  default: [json, md]
      responses:
        '200':
          description: SSE stream of extraction progress events
          content:
            text/event-stream:
              schema:
                type: string
  /enaibleusovereignty/api/v1/spectre/extract/jobs:
    get:
      summary: Spectre Extract — List Jobs
      description: List all site extraction jobs. Admin session required.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Array of extraction jobs
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id: {type: string}
                    root_url: {type: string}
                    status:
                      type: string
                      enum: [running, done, failed]
                    config:
                      type: object
                      properties:
                        max_depth: {type: integer}
                        max_pages: {type: integer}
                        hop_external: {type: boolean}
                        formats:
                          type: array
                          items: {type: string}
                    stats:
                      type: object
                      properties:
                        pages_extracted: {type: integer}
                        internal_links: {type: integer}
                        external_domains: {type: integer}
                        words_extracted: {type: integer}
                        duration_ms: {type: integer}
                    external_domains:
                      type: array
                      items: {type: string}
                    output_json_path: {type: string}
                    output_md_path: {type: string}
                    created_at: {type: string}
                    updated_at: {type: string}
  /enaibleusovereignty/api/v1/spectre/extract/job:
    get:
      summary: Spectre Extract — Get Job
      description: Get a single extraction job with full page data (loaded from disk). Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Full extraction job with pages
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: {type: string}
                  root_url: {type: string}
                  status:
                    type: string
                    enum: [running, done, failed]
                  config:
                    type: object
                    properties:
                      max_depth: {type: integer}
                      max_pages: {type: integer}
                      hop_external: {type: boolean}
                      formats:
                        type: array
                        items: {type: string}
                  stats:
                    type: object
                    properties:
                      pages_extracted: {type: integer}
                      internal_links: {type: integer}
                      external_domains: {type: integer}
                      words_extracted: {type: integer}
                      duration_ms: {type: integer}
                  external_domains:
                    type: array
                    items: {type: string}
                  output_json_path: {type: string}
                  output_md_path: {type: string}
                  created_at: {type: string}
                  updated_at: {type: string}
  /enaibleusovereignty/api/v1/spectre/extract/delete:
    post:
      summary: Spectre Extract — Delete Job
      description: Delete an extraction job and its output files. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                id: {type: string}
      responses:
        '200':
          description: Deleted
  /enaibleusovereignty/api/v1/spectre/extract/export:
    get:
      summary: Spectre Extract — Export Job
      description: Download extraction output as JSON or Markdown file. Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
        - name: format
          in: query
          schema:
            type: string
            enum: [json, md]
            default: json
      responses:
        '200':
          description: File download
          content:
            application/json:
              schema:
                type: object
            text/markdown:
              schema:
                type: string

  # Spectre Map — Site Structure Discovery
  /enaibleusovereignty/api/v1/spectre/map:
    post:
      summary: Spectre Map — Site Structure Discovery
      description: |
        Discovers the structure of a website. Checks sitemap.xml / sitemap_index.xml first (instant),
        falls back to a shallow nav crawl if no sitemap is found. Returns a hierarchical page tree.
        Much faster than full extraction — use when you need topology without content. Pro session required.
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  description: Root URL of the site to map
      responses:
        '200':
          description: Site map result
          content:
            application/json:
              schema:
                type: object
                properties:
                  root_url: {type: string}
                  source: {type: string, enum: [sitemap_xml, sitemap_index, crawl, mixed]}
                  page_count: {type: integer}
                  duration_ms: {type: integer}
                  pages:
                    type: array
                    items:
                      type: object
                      properties:
                        url: {type: string}
                        title: {type: string}
                        depth: {type: integer}
                        change_freq: {type: string}
                        priority: {type: number}
                  tree:
                    type: object
                    description: Hierarchical tree of SiteMapNode

  # Spectre Images — Image Extractor
  /enaibleusovereignty/api/v1/spectre/images:
    post:
      summary: Spectre Images — Extract Images from URL
      description: |
        Extracts all images from a URL with alt text, OG image detection, and nearest heading context.
        Images are stripped from Markdown output to save tokens — use this endpoint when you need
        to specifically analyze or reference visual content. Pro session required.
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  description: URL to extract images from
      responses:
        '200':
          description: Image extraction result
          content:
            application/json:
              schema:
                type: object
                properties:
                  url: {type: string}
                  final_url: {type: string}
                  image_count: {type: integer}
                  og_image: {type: string}
                  duration_ms: {type: integer}
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        src: {type: string}
                        url: {type: string}
                        alt: {type: string}
                        context: {type: string, description: Nearest heading or paragraph context}
                        is_og: {type: boolean}

  # Spectre Keywords — Page Keyword Rankings
  /enaibleusovereignty/api/v1/spectre/keywords:
    get:
      summary: Spectre Keywords — Ranked Keyword Records
      description: |
        Retrieves ranked keyword records from the database for a specific URL or domain.
        Keywords are scored by extraction tier: H1 (1.0), title (0.8), H2 (0.85), meta (0.75),
        analysis tags (0.7), H3 (0.65), body frequency (0.3–0.6). Persisted automatically
        during every Fetch and Extract operation. Pro session required.
      security:
        - cookieAuth: []
      parameters:
        - name: url
          in: query
          schema: {type: string}
          description: Filter by exact URL
        - name: domain
          in: query
          schema: {type: string}
          description: Filter by domain (e.g. example.com)
      responses:
        '200':
          description: Array of page keyword records
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    url: {type: string}
                    domain: {type: string}
                    title: {type: string}
                    word_count: {type: integer}
                    source: {type: string, enum: [fetch, extract, scout]}
                    crawled_at: {type: string, format: date-time}
                    keywords:
                      type: array
                      items:
                        type: object
                        properties:
                          term: {type: string}
                          score: {type: number, minimum: 0, maximum: 1}
                          category: {type: string, enum: [heading, meta, content, tag]}

  # Sentinel AI Model Hub
  /enaibleusovereignty/api/v1/sentinel/ai-models:
    get:
      summary: AI Model Hub — List Models
      description: List all AI models in the hub with filtering. Admin session required.
      security:
        - cookieAuth: []
      parameters:
        - name: provider
          in: query
          schema:
            type: string
        - name: tag
          in: query
          schema:
            type: string
        - name: speed_tier
          in: query
          schema:
            type: string
        - name: free_only
          in: query
          schema:
            type: boolean
      responses:
        '200':
          description: Array of AI models
  /enaibleusovereignty/api/v1/sentinel/ai-models/sync:
    post:
      summary: AI Model Hub — Sync from OpenRouter
      description: Fetch latest models from OpenRouter API and upsert into the hub. Detects changelog changes. Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Sync result with counts
  /enaibleusovereignty/api/v1/sentinel/ai-models/enrich:
    post:
      summary: AI Model Hub — LLM Enrich Models
      description: Use LLM to analyse models and populate capabilities, best_for, avoid_when, call examples. Background P2 priority. Admin session required.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: string
                  description: Specific model ID to enrich (omit to enrich all unenriched)
      responses:
        '200':
          description: Enrichment started
  /enaibleusovereignty/api/v1/sentinel/ai-models/scrape-nvidia:
    post:
      summary: AI Model Hub — Scrape NVIDIA NIM
      description: Scrape NVIDIA NIM model cards via Spectre and upsert into hub. Admin session required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Scrape result
  /enaibleusovereignty/api/v1/sentinel/ai-models/scrape-huggingface:
    post:
      summary: AI Model Hub — Scrape HuggingFace
      description: Scrape HuggingFace model cards via Spectre and upsert into hub. Pro tier required.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Scrape result
  /enaibleusovereignty/api/v1/sentinel/ai-models/{id}:
    get:
      summary: AI Model Hub — Get Model
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: AI model detail
    put:
      summary: AI Model Hub — Update Model
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated model
    delete:
      summary: AI Model Hub — Delete Model
      security:
        - cookieAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Deleted
  /enaibleusovereignty/api/v1/sentinel/ai-collections:
    get:
      summary: AI Model Hub — List Collections
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Curated model collections
    post:
      summary: AI Model Hub — Create Collection
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name: {type: string}
                description: {type: string}
                model_ids:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Created collection
  /enaibleusovereignty/api/v1/sentinel/ai-changelog:
    get:
      summary: AI Model Hub — Changelog
      description: Recent model changes detected during sync (new models, pricing changes, etc.)
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Changelog entries
  /enaibleusovereignty/api/v1/sentinel/ai-providers:
    get:
      summary: AI Model Hub — List Providers
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Provider list

  /enaibleusovereignty/api/v1/nexus/mcp-vault/secrets:
    get:
      summary: List MCP Vault Secrets
      description: Returns metadata for all AI-accessible secrets (values are encrypted).
      security:
        - cookieAuth: []
      responses:
        '200':
          description: List of MCP secrets
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  secrets:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        label:
                          type: string
                        description:
                          type: string
                        allowed_tools:
                          type: array
                          items:
                            type: string
                        is_sensitive:
                          type: boolean
                        access_count:
                          type: integer
                        last_accessed:
                          type: string
                        created:
                          type: string
                        updated:
                          type: string
                  count:
                    type: integer
  /enaibleusovereignty/api/v1/nexus/mcp-vault/secrets/publish:
    post:
      summary: Publish Secret to MCP Vault
      description: Publishes a secret from the user's vault to the AI-accessible MCP vault.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [name, value]
              properties:
                source_secret_id:
                  type: string
                  description: Optional ID of the source secret in user's vault
                name:
                  type: string
                  description: Unique name for the MCP secret
                value:
                  type: string
                  description: The plaintext secret value (will be encrypted)
                label:
                  type: string
                  description: Human-readable label
                description:
                  type: string
                allowed_tools:
                  type: array
                  items:
                    type: string
                  description: Tools allowed to access this secret (default ["*"])
                is_sensitive:
                  type: boolean
      responses:
        '200':
          description: Secret published successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
  /enaibleusovereignty/api/v1/nexus/mcp-vault/secrets/revoke:
    post:
      summary: Revoke MCP Vault Secret
      description: Removes a secret from the AI-accessible MCP vault.
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  description: Name of the secret to revoke
      responses:
        '200':
          description: Secret revoked successfully
  /enaibleusovereignty/api/v1/nexus/mcp-vault/stats:
    get:
      summary: Get MCP Vault Statistics
      description: Returns usage statistics for the user's MCP vault.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Vault statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  total_secrets:
                    type: integer
                  accessed_count:
                    type: integer
                  unused_count:
                    type: integer
  # Vault (Personal Secret Store) - v9.0.0
  /enaibleusovereignty/api/v1/vault:
    get:
      summary: List Vault Secrets
      description: Get all secret metadata (names, labels) from user's vault
      security:
        - cookieAuth: []
      responses:
        '200':
          description: List of secrets
    post:
      summary: Create/Update Secret
      description: Write a secret to the vault
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name: {type: string}
                value: {type: string}
                label: {type: string}
                description: {type: string}
      responses:
        '200':
          description: Secret saved
  /enaibleusovereignty/api/v1/vault/status:
    get:
      summary: Vault Status
      description: Check if vault is sealed/unsealed
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Vault status
  /enaibleusovereignty/api/v1/vault/unseal:
    post:
      summary: Unseal Vault
      description: Unlock the vault with master key
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                master_key: {type: string}
      responses:
        '200':
          description: Vault unsealed
  /enaibleusovereignty/api/v1/vault/seal:
    post:
      summary: Seal Vault
      description: Lock the vault
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Vault sealed

  # Subscriptions & Billing - v9.0.0
  /enaibleusovereignty/api/v1/subscription/plans:
    get:
      summary: List Subscription Plans
      description: Get available plans (Free, Pro, Enterprise)
      responses:
        '200':
          description: List of plans
  /enaibleusovereignty/api/v1/subscription/create:
    post:
      summary: Create Subscription
      description: Create a PayPal subscription
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                plan_id: {type: string}
      responses:
        '200':
          description: Subscription created with approval URL
  /enaibleusovereignty/api/v1/subscription/cancel:
    post:
      summary: Cancel Subscription
      description: Cancel current PayPal subscription
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Subscription cancelled
  /enaibleusovereignty/api/v1/subscription/status:
    get:
      summary: Get Subscription Status
      description: Get user's current subscription
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Subscription status
  /enaibleusovereignty/api/v1/subscription/webhook:
    post:
      summary: PayPal Webhook
      description: Handle PayPal billing events
      responses:
        '200':
          description: Webhook processed

  /enaibleusovereignty/api/v1/sentinel/routing/ops:
    get:
      summary: Get Routing Config
      description: Get model routing operations
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Routing config
  /enaibleusovereignty/api/v1/sentinel/routing/apply:
    post:
      summary: Apply Routing Config
      description: Update runtime model routing
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Config applied

  # Profile Endpoints
  /enaibleusovereignty/api/v1/profile:
    get:
      summary: Get current user profile
      responses:
        '200':
          description: User profile
    patch:
      summary: Update current user profile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated profile
  /enaibleusovereignty/api/v1/profile/mail-accounts:
    get:
      summary: List mail accounts for current user
      responses:
        '200':
          description: Mail accounts list
  /enaibleusovereignty/api/v1/profile/master-key:
    post:
      summary: Set master key for current user vault
      responses:
        '200':
          description: Master key set
    delete:
      summary: Remove master key
      responses:
        '200':
          description: Master key removed
  /enaibleusovereignty/api/v1/profile/vault-devices:
    get:
      summary: List trusted vault devices
      responses:
        '200':
          description: Device list
    post:
      summary: Register a trusted vault device
      responses:
        '200':
          description: Device registered
    delete:
      summary: Remove all trusted vault devices
      responses:
        '200':
          description: Devices removed

  # Mail — Email Management
  /enaibleusovereignty/api/v1/mail/emails:
    get:
      summary: List emails for current user
      responses:
        '200':
          description: Email list
    delete:
      summary: Delete an email
      responses:
        '200':
          description: Email deleted
  /enaibleusovereignty/api/v1/mail/emails/view:
    get:
      summary: View/render an email
      responses:
        '200':
          description: Email content
  /enaibleusovereignty/api/v1/mail/emails/bulk-delete:
    post:
      summary: Bulk delete emails
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Emails deleted

  # Notifications
  /enaibleusovereignty/api/v1/notifications/stats:
    get:
      summary: Get notification hub stats
      responses:
        '200':
          description: Stats
  /enaibleusovereignty/api/v1/notifications/broadcast:
    post:
      summary: Broadcast a notification to all connected clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Broadcast sent
  /enaibleusovereignty/api/v1/notifications/ws:
    get:
      summary: WebSocket endpoint for real-time notifications
      responses:
        '101':
          description: Switching Protocols

  # Memory — Additional Endpoints
  /enaibleusovereignty/api/v1/memory:
    get:
      summary: Get memory status/overview
      responses:
        '200':
          description: Memory overview
  /enaibleusovereignty/api/v1/memory/list:
    get:
      summary: List memory entries
      responses:
        '200':
          description: Memory entries
  /enaibleusovereignty/api/v1/memory/stores:
    get:
      summary: List available memory stores
      responses:
        '200':
          description: Memory stores
  /enaibleusovereignty/api/v1/memory/semantic-search:
    get:
      summary: Search memories with enhanced semantic scoring
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
        - name: semantic
          in: query
          required: false
          schema:
            type: boolean
      responses:
        '200':
          description: Semantic memory search results
  /enaibleusovereignty/api/v1/memory/categories:
    get:
      summary: List memory categories
      responses:
        '200':
          description: Category counts
  /enaibleusovereignty/api/v1/memory/cleanup:
    post:
      summary: Cleanup expired or over-limit memories
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                dry_run:
                  type: boolean
                user_id:
                  type: string
                max_memories:
                  type: integer
      responses:
        '200':
          description: Cleanup summary
  /enaibleusovereignty/api/v1/memory/enrich-agents:
    post:
      summary: Enrich unenriched agent_learning memories
      description: Batch-enriches agent_learning and agent-type memories that have not yet been through the LLM enrichment pipeline (keyword extraction, entity detection, sentiment scoring, importance rating). Called by the Memory Enricher cascade on startup and nightly at 04:00.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                limit:
                  type: integer
                  default: 100
                  description: Maximum number of memories to process in one call
      responses:
        '200':
          description: Enrichment summary
          content:
            application/json:
              schema:
                type: object
                properties:
                  enriched: {type: integer}
                  failed: {type: integer}
                  total_processed: {type: integer}
        '500':
          description: Internal error during enrichment
  /enaibleusovereignty/api/v1/memory/re-enrich:
    post:
      summary: Re-enrich legacy memories with compound disambiguation keywords
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                scope:
                  type: string
                  enum: [mine, global, all]
                force:
                  type: boolean
                limit:
                  type: integer
      responses:
        '200':
          description: Re-enrichment summary
  /enaibleusovereignty/api/v1/memory/docs:
    get:
      summary: List indexed documents in memory
      responses:
        '200':
          description: Document list
  /enaibleusovereignty/api/v1/index/search:
    get:
      summary: Search the unified sovereign index across docs, memories, screenshots, extractions, and images
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
        - name: kinds
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated kinds filter. Supported values: docs, memories, screenshots, extractions, images."
      responses:
        '200':
          description: Unified index search results
  /enaibleusovereignty/api/v1/memory/context:
    post:
      summary: Get assembled context for a query
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  type: string
      responses:
        '200':
          description: Assembled context
  /enaibleusovereignty/api/v1/memory/remember:
    post:
      summary: Store a memory entry
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Memory stored
  /enaibleusovereignty/api/v1/memory/delete:
    post:
      summary: Delete a memory entry
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: string
      responses:
        '200':
          description: Memory deleted

  # MCP
  /enaibleusovereignty/api/v1/mcp/execute:
    post:
      summary: Execute an MCP tool call
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tool:
                  type: string
                params:
                  type: object
      responses:
        '200':
          description: Tool execution result

  # Auth — OAuth
  /enaibleusovereignty/api/v1/auth/oauth/providers:
    get:
      summary: List available OAuth providers
      responses:
        '200':
          description: Provider list
  /enaibleusovereignty/api/v1/auth/oauth/complete:
    post:
      summary: Complete OAuth flow and create session
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Session created

  # Documents
  /enaibleusovereignty/api/v1/documents/content:
    get:
      summary: Get document content by path
      parameters:
        - in: query
          name: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Document content

  # Models Routing
  /enaibleusovereignty/api/v1/models/routing:
    get:
      summary: Get current AI model routing configuration
      responses:
        '200':
          description: Routing config

  # Blog
  /enaibleusovereignty/api/v1/blog:
    get:
      summary: List blog posts
      responses:
        '200':
          description: Blog post list
  /enaibleusovereignty/api/v1/blog/submit:
    post:
      summary: Submit a new blog post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Blog post submitted

  # Healer
  /enaibleusovereignty/api/v1/healer/reports:
    get:
      summary: List system health reports from Healer
      responses:
        '200':
          description: Health reports

  # Vault — Additional Endpoints
  /enaibleusovereignty/api/v1/vault/audit:
    get:
      summary: Get vault audit log
      responses:
        '200':
          description: Audit log entries
  /enaibleusovereignty/api/v1/vault/auto-unseal:
    post:
      summary: Auto-unseal vault using configured master key
      responses:
        '200':
          description: Vault unsealed
  /enaibleusovereignty/api/v1/vault/seed-from-env:
    post:
      summary: Seed vault secrets from VAULT_SECRET_* environment variables
      responses:
        '200':
          description: Secrets seeded
  /enaibleusovereignty/api/v1/vault/secrets/{id}:
    get:
      summary: Read a vault secret by name
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Secret value
    delete:
      summary: Delete a vault secret
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Secret deleted

  # Screenshots
  /enaibleusovereignty/api/v1/screenshots/{filename}:
    get:
      summary: Serve a captured screenshot
      parameters:
        - in: path
          name: filename
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Screenshot image

  # Sentinel — Additional Endpoints
  /enaibleusovereignty/api/v1/sentinel/expenses:
    get:
      summary: List expenses
      responses:
        '200':
          description: Expense list
    post:
      summary: Create an expense
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '201':
          description: Expense created
  /enaibleusovereignty/api/v1/sentinel/expenses/{id}:
    patch:
      summary: Update an expense
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Expense updated
    delete:
      summary: Delete an expense
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Expense deleted
  /enaibleusovereignty/api/v1/sentinel/income:
    get:
      summary: List income records
      responses:
        '200':
          description: Income list
    post:
      summary: Create an income record
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '201':
          description: Income created
  /enaibleusovereignty/api/v1/sentinel/income/{id}:
    patch:
      summary: Update an income record
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Income updated
    delete:
      summary: Delete an income record
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Income deleted
  /enaibleusovereignty/api/v1/sentinel/deals:
    get:
      summary: List MEDDPICC Deals
      description: List all deals for the authenticated user with scores and statuses.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Deal list
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  deals:
                    type: array
                    items:
                      $ref: '#/components/schemas/Deal'
        '401':
          description: Unauthorized
    post:
      summary: Create Deal + Trigger MEDDPICC Analysis
      description: Accept deal text, PDF, or DOCX and trigger async LLM scoring. Returns 202 with deal id and initial status.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Deal display name
                source_type:
                  type: string
                  enum: [text, pdf, docx]
                content:
                  type: string
                  description: Plain-text deal notes (when source_type=text)
                file:
                  type: string
                  format: binary
                  description: Uploaded PDF or DOCX file
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                source_type:
                  type: string
                  enum: [text]
                content:
                  type: string
      responses:
        '202':
          description: Deal created; analysis in progress
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  status:
                    type: string
                    enum: [analyzing]
        '400':
          description: Invalid request
        '401':
          description: Unauthorized
  /enaibleusovereignty/api/v1/sentinel/deals/{id}:
    get:
      summary: Get Deal
      description: Retrieve a single deal with full decrypted MEDDPICC feedback.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Deal detail
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '401':
          description: Unauthorized
        '404':
          description: Deal not found
    delete:
      summary: Delete Deal
      description: Permanently delete a deal and its encrypted content.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Deal deleted
        '401':
          description: Unauthorized
        '404':
          description: Deal not found
  /enaibleusovereignty/api/v1/sentinel/deals/{id}/reanalyze:
    post:
      summary: Re-analyze Deal
      description: Re-run the MEDDPICC LLM analysis on an existing deal.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '202':
          description: Re-analysis triggered
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  status:
                    type: string
                    enum: [analyzing]
        '401':
          description: Unauthorized
        '404':
          description: Deal not found
  /enaibleusovereignty/api/v1/sentinel/deals/coach:
    post:
      summary: AI Sales Manager Coaching
      description: Ask the AI Sales Manager a coaching question scoped to a deal category or full deal context.
      tags: [Sentinel]
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [question]
              properties:
                question:
                  type: string
                  description: The coaching question to answer
                category:
                  type: string
                  description: MEDDPICC category to focus on (e.g. champion, economic_buyer)
                  enum: [metrics, economic_buyer, decision_criteria, decision_process, paper_process, identify_pain, champion, competition]
                deal_context:
                  type: string
                  description: Raw deal context to include (optional if deal_summary provided)
                deal_summary:
                  type: string
                  description: Pre-built deal summary string (optional)
      responses:
        '200':
          description: Coaching answer
          content:
            application/json:
              schema:
                type: object
                properties:
                  answer:
                    type: string
                  model:
                    type: string
        '400':
          description: Invalid request
        '401':
          description: Unauthorized
  /enaibleusovereignty/api/v1/sentinel/internal-domains:
    get:
      summary: List internal domains
      responses:
        '200':
          description: Internal domains
    post:
      summary: Add an internal domain
      responses:
        '201':
          description: Domain added
  /enaibleusovereignty/api/v1/sentinel/internal-domains/{id}:
    delete:
      summary: Remove an internal domain
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Domain removed
  /enaibleusovereignty/api/v1/sentinel/routing/import-yaml:
    post:
      summary: Import routing configuration from YAML
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Routing config imported
  /enaibleusovereignty/api/v1/sentinel/routing/models:
    get:
      summary: List routing model overrides
      responses:
        '200':
          description: Model overrides
  /enaibleusovereignty/api/v1/sentinel/secrets:
    get:
      summary: List sentinel-managed secrets (names only)
      responses:
        '200':
          description: Secret names
  /enaibleusovereignty/api/v1/sentinel/secrets/audit:
    get:
      summary: Get sentinel secrets audit log
      responses:
        '200':
          description: Audit log
  /enaibleusovereignty/api/v1/sentinel/secrets/status:
    get:
      summary: Get sentinel secrets vault status
      responses:
        '200':
          description: Vault status
  /enaibleusovereignty/api/v1/sentinel/secrets/unseal:
    post:
      summary: Unseal sentinel secrets vault
      responses:
        '200':
          description: Vault unsealed
  /enaibleusovereignty/api/v1/sentinel/secrets/seal:
    post:
      summary: Seal sentinel secrets vault
      responses:
        '200':
          description: Vault sealed
  /enaibleusovereignty/api/v1/sentinel/secrets/auto-unseal:
    post:
      summary: Auto-unseal sentinel vault from environment
      responses:
        '200':
          description: Vault auto-unsealed
  /enaibleusovereignty/api/v1/sentinel/secrets/seed-from-env:
    post:
      summary: Seed sentinel vault from VAULT_SECRET_* env vars
      responses:
        '200':
          description: Secrets seeded
  /enaibleusovereignty/api/v1/sentinel/todos/board:
    get:
      summary: Get Kanban board state
      description: "Returns all todos grouped into the four status columns: intake, in_progress, done_evaluation, archived. Each column is sorted by sort_order."
      parameters:
        - name: user_id
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: "Board columns with todos"
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  columns:
                    type: array
                    items:
                      type: object
                      properties:
                        status:
                          type: string
                          enum: [intake, in_progress, done_evaluation, archived]
                        label:
                          type: string
                        todos:
                          type: array
                          items:
                            $ref: '#/components/schemas/Todo'
  /enaibleusovereignty/api/v1/sentinel/todos:
    get:
      summary: List todos
      parameters:
        - name: user_id
          in: query
          required: true
          schema:
            type: string
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [intake, in_progress, done_evaluation, archived]
        - name: parent_id
          in: query
          required: false
          schema:
            type: string
        - name: category
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Todo list
    post:
      summary: Create a todo
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTodoRequest'
      responses:
        '201':
          description: Todo created
  /enaibleusovereignty/api/v1/sentinel/todos/{id}:
    get:
      summary: Get a single todo
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Todo record
    put:
      summary: Update a todo
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTodoRequest'
      responses:
        '200':
          description: Todo updated
    delete:
      summary: Delete a todo
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Todo deleted
  /enaibleusovereignty/api/v1/sentinel/todos/{id}/move:
    patch:
      summary: Move todo to a different status column
      description: "Drag-and-drop equivalent — changes the todo's status and sort_order. Used by the Kanban board UI and by the AI via mcp_sentinel_move_todo."
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status]
              properties:
                status:
                  type: string
                  enum: [intake, in_progress, done_evaluation, archived]
                sort_order:
                  type: integer
      responses:
        '200':
          description: Todo moved

  # Nexus — Additional Endpoints
  /enaibleusovereignty/api/v1/nexus/reports:
    get:
      summary: List Nexus reports
      description: Returns paginated nexus_reports entries (enrichment, lint, audit, janitor). Supports filter, sort, page, perPage.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: page
          in: query
          schema: {type: integer}
        - name: perPage
          in: query
          schema: {type: integer}
        - name: filter
          in: query
          schema: {type: string}
        - name: sort
          in: query
          schema: {type: string}
      responses:
        '200':
          description: Reports list

  # Nexus Report Share Links
  /enaibleusovereignty/api/v1/nexus/reports/{id}/share:
    post:
      summary: Create a permanent share link for a report
      description: Mints a 32-byte hex token stored in nexus_document_shares. The resulting /d/{token} URL is publicly accessible with no authentication required.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
          description: Nexus report ID
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type: string
                  description: Optional human-readable label for the share link
                expires_at:
                  type: string
                  format: date-time
                  description: Optional expiry timestamp (RFC3339). Omit for a permanent link.
      responses:
        '200':
          description: Share link created
          content:
            application/json:
              schema:
                type: object
                properties:
                  token: {type: string}
                  url: {type: string}
                  label: {type: string}
                  expires_at: {type: string}
        '404':
          description: Report not found
  /enaibleusovereignty/api/v1/nexus/shares:
    get:
      summary: List all active share links
      description: Returns all nexus_document_shares records for the authenticated user.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Share link list
          content:
            application/json:
              schema:
                type: object
                properties:
                  shares:
                    type: array
                    items:
                      type: object
                      properties:
                        token: {type: string}
                        report_id: {type: string}
                        label: {type: string}
                        created_by: {type: string}
                        created: {type: string}
                        expires_at: {type: string}
                        access_count: {type: integer}
  /enaibleusovereignty/api/v1/nexus/shares/{token}:
    delete:
      summary: Revoke a share link
      description: Deletes the nexus_document_shares record, immediately invalidating the public URL.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: token
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Share revoked
        '404':
          description: Token not found

  # Public Document Share View
  /enaibleusovereignty/api/v1/d/{token}:
    get:
      summary: Fetch shared document by token
      description: Public endpoint (no auth). Validates the token, checks expiry, increments access_count, and returns report data. This is called by the /d/{token} frontend route.
      parameters:
        - name: token
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Shared document data
          content:
            application/json:
              schema:
                type: object
                properties:
                  report:
                    type: object
                    properties:
                      id: {type: string}
                      title: {type: string}
                      content: {type: string}
                      type: {type: string}
                      status: {type: string}
                      created: {type: string}
                  share:
                    type: object
                    properties:
                      token: {type: string}
                      label: {type: string}
                      created_by: {type: string}
                      created: {type: string}
                      expires_at: {type: string}
                      access_count: {type: integer}
                  public: {type: boolean}
        '404':
          description: Token not found or expired

  # Nexus Rewards — Agent Gamification
  /enaibleusovereignty/api/v1/nexus/rewards/agents:
    get:
      summary: List agent profiles
      description: Returns all sovereign agent profiles with name, avatar, XP totals, and level.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Agent profile list
  /enaibleusovereignty/api/v1/nexus/rewards/work:
    get:
      summary: List agent work outputs
      description: Returns paginated work feed from nexus_work_outputs. Filter by agent_id, task_type, or approval status.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: agent
          in: query
          schema: {type: string}
        - name: limit
          in: query
          schema: {type: integer}
      responses:
        '200':
          description: Work output feed
  /enaibleusovereignty/api/v1/nexus/rewards/work/content:
    get:
      summary: Read full work output file
      description: Returns the full content of a work output artifact by ID.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Work output content
  /enaibleusovereignty/api/v1/nexus/rewards/work/approve:
    post:
      summary: Approve agent work + award bonus XP
      description: Marks a work output as approved and awards bonus XP to the agent.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                work_id: {type: string}
                bonus_xp: {type: integer}
      responses:
        '200':
          description: Approved
  /enaibleusovereignty/api/v1/nexus/rewards/award:
    post:
      summary: Manually award XP to an agent
      description: Admin endpoint to manually credit XP to a named agent profile.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                agent_id: {type: string}
                event_type: {type: string}
                reason: {type: string}
                xp: {type: integer}
      responses:
        '200':
          description: XP awarded
  /enaibleusovereignty/api/v1/nexus/rewards/events:
    get:
      summary: List XP events
      description: Returns the XP event log for agents. Supports filter by agent_id.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: XP event list
  /enaibleusovereignty/api/v1/nexus/rewards/skills:
    get:
      summary: List agent skill levels
      description: Returns aggregated skill-level data per agent.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Skill levels

  /enaibleusovereignty/api/v1/nexus/janitor-reports:
    get:
      summary: List Nexus janitor cleanup reports
      responses:
        '200':
          description: Janitor reports

  # Spectre — Additional Endpoints
  /enaibleusovereignty/api/v1/spectre/assets:
    get:
      summary: List tracked domain assets
      responses:
        '200':
          description: Asset list
  /enaibleusovereignty/api/v1/spectre/assets/analyze:
    post:
      summary: Analyze a domain asset
      responses:
        '200':
          description: Analysis result
  /enaibleusovereignty/api/v1/spectre/assets/mark-bought:
    post:
      summary: Mark a domain asset as purchased
      responses:
        '200':
          description: Asset updated
  /enaibleusovereignty/api/v1/spectre/assets/verify:
    post:
      summary: Verify domain asset ownership
      responses:
        '200':
          description: Verification result
  /enaibleusovereignty/api/v1/spectre/campaigns/targets:
    get:
      summary: List campaign targets
      responses:
        '200':
          description: Target list
  /enaibleusovereignty/api/v1/spectre/campaigns/targets/hidden:
    get:
      summary: List hidden campaign targets
      responses:
        '200':
          description: Hidden target list
  /enaibleusovereignty/api/v1/spectre/campaigns/run:
    post:
      summary: Run a link-building campaign
      responses:
        '200':
          description: Campaign started
  /enaibleusovereignty/api/v1/spectre/campaigns/results:
    get:
      summary: Get campaign results
      responses:
        '200':
          description: Campaign results
  /enaibleusovereignty/api/v1/spectre/campaigns/findings:
    get:
      summary: Get campaign findings
      responses:
        '200':
          description: Findings
  /enaibleusovereignty/api/v1/spectre/campaigns/opportunities:
    get:
      summary: Get link-building opportunities
      responses:
        '200':
          description: Opportunities
  /enaibleusovereignty/api/v1/spectre/campaigns/target-override:
    post:
      summary: Set a campaign target override
      responses:
        '200':
          description: Override set
  /enaibleusovereignty/api/v1/spectre/campaigns/target-override/delete:
    post:
      summary: Remove a campaign target override
      responses:
        '200':
          description: Override removed
  /enaibleusovereignty/api/v1/spectre/domains-vault:
    get:
      summary: List domains vault entries
      responses:
        '200':
          description: Domains vault list
  /enaibleusovereignty/api/v1/spectre/domains-vault/{id}:
    delete:
      summary: Delete a domains vault entry
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Entry deleted
  /enaibleusovereignty/api/v1/spectre/domains-vault/intelligence/refresh:
    post:
      summary: Refresh intelligence for a domains vault entry
      responses:
        '200':
          description: Intelligence refreshed
  /enaibleusovereignty/api/v1/spectre/findings/export:
    get:
      summary: Export spectre findings as CSV/JSON
      responses:
        '200':
          description: Exported findings
  /enaibleusovereignty/api/v1/spectre/health/exclusions:
    get:
      summary: List link health exclusions
      responses:
        '200':
          description: Exclusion list
  /enaibleusovereignty/api/v1/spectre/health/save:
    post:
      summary: Save link health scan results
      responses:
        '200':
          description: Results saved
  /enaibleusovereignty/api/v1/spectre/health/stream:
    get:
      summary: Stream link health scan progress (SSE)
      responses:
        '200':
          description: SSE stream
  /enaibleusovereignty/api/v1/spectre/hopper:
    get:
      summary: List hopper (link queue) entries
      responses:
        '200':
          description: Hopper entries
  /enaibleusovereignty/api/v1/spectre/hopper/status:
    get:
      summary: Get hopper status
      responses:
        '200':
          description: Hopper status
  /enaibleusovereignty/api/v1/spectre/hopper/label:
    post:
      summary: Label a hopper entry
      responses:
        '200':
          description: Entry labelled
  /enaibleusovereignty/api/v1/spectre/hopper/delete:
    post:
      summary: Delete hopper entries
      responses:
        '200':
          description: Entries deleted
  /enaibleusovereignty/api/v1/spectre/metrics:
    get:
      summary: Get Spectre performance metrics
      responses:
        '200':
          description: Metrics
  /enaibleusovereignty/api/v1/spectre/metrics/clear:
    post:
      summary: Clear Spectre metrics
      responses:
        '200':
          description: Metrics cleared
  /enaibleusovereignty/api/v1/spectre/outreach/seeds:
    get:
      summary: List outreach seed sites
      responses:
        '200':
          description: Seed list
  /enaibleusovereignty/api/v1/spectre/outreach/seeds/delete:
    post:
      summary: Delete an outreach seed
      responses:
        '200':
          description: Seed deleted
  /enaibleusovereignty/api/v1/spectre/outreach/run:
    post:
      summary: Run outreach campaign
      responses:
        '200':
          description: Campaign started
  /enaibleusovereignty/api/v1/spectre/scans:
    get:
      summary: List active/recent scans
      responses:
        '200':
          description: Scan list
  /enaibleusovereignty/api/v1/spectre/scans/stop:
    post:
      summary: Stop a running scan
      responses:
        '200':
          description: Scan stopped
  /enaibleusovereignty/api/v1/spectre/scans/delete:
    post:
      summary: Delete a scan record
      responses:
        '200':
          description: Scan deleted
  /enaibleusovereignty/api/v1/spectre/suppressed-domains:
    get:
      summary: List suppressed domains (excluded from scans)
      responses:
        '200':
          description: Suppressed domain list
  /enaibleusovereignty/api/v1/spectre/targets/delete:
    post:
      summary: Delete a spectre target
      responses:
        '200':
          description: Target deleted

  # ── Workbench Connectors ─────────────────────────────────────────────────
  /enaibleusovereignty/api/v1/workbench/connectors:
    get:
      tags: [Workbench Connectors]
      summary: List all connectors for the authenticated user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Connector list
          content:
            application/json:
              schema:
                type: object
                properties:
                  connectors:
                    type: array
                    items:
                      $ref: '#/components/schemas/Connector'
    post:
      tags: [Workbench Connectors]
      summary: Create a new connector
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConnectorRequest'
      responses:
        '201':
          description: Connector created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: {type: string}
                  success: {type: boolean}
        '400':
          description: Validation error

  /enaibleusovereignty/api/v1/workbench/connectors/{id}:
    get:
      tags: [Workbench Connectors]
      summary: Get a single connector
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Connector record
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Connector'
        '404':
          description: Not found
    put:
      tags: [Workbench Connectors]
      summary: Update a connector
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConnectorRequest'
      responses:
        '200':
          description: Updated
        '404':
          description: Not found
    delete:
      tags: [Workbench Connectors]
      summary: Delete a connector
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted
        '404':
          description: Not found

  /enaibleusovereignty/api/v1/workbench/connectors/{id}/test:
    post:
      tags: [Workbench Connectors]
      summary: Live-test a connector's credentials
      description: >
        Attempts a real authentication handshake against the target service
        (Microsoft OAuth2 token endpoint, Salesforce REST auth, or Slack auth.test)
        and persists the resulting status back to the connector record.
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Test result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  status:
                    type: string
                    enum: [connected, error]
                  error: {type: string, description: Present when success is false}
        '404':
          description: Connector not found

  /enaibleusovereignty/api/v1/nexus/translate:
    post:
      tags: [Nexus Translate]
      summary: Translate content between languages using LLM
      description: >
        Translates plain text, Markdown, or JSON between any supported language pair.
        The source format is auto-detected when not specified. Returns the translated
        content with word count and duration metrics. Set `download: true` to receive
        the result as a downloadable file (binary response).
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TranslateRequest'
      responses:
        '200':
          description: Translation result (JSON) or file download (binary)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TranslateResult'
            text/plain:
              schema:
                type: string
                format: binary
            text/markdown:
              schema:
                type: string
                format: binary
        '400':
          description: Bad request — missing or invalid fields
        '500':
          description: LLM translation error

  /enaibleusovereignty/api/v1/nexus/translate/languages:
    get:
      tags: [Nexus Translate]
      summary: List supported translation languages
      description: Returns the list of languages available for translation.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Supported languages
          content:
            application/json:
              schema:
                type: object
                properties:
                  languages:
                    type: array
                    items:
                      type: object
                      properties:
                        code:  {type: string, example: ENG}
                        label: {type: string, example: English}
                        flag:  {type: string, example: "🇬🇧"}

  # Nexus Cascade Categories — user-defined kanban columns for the Cascades board
  /enaibleusovereignty/api/v1/nexus/cascade-categories:
    get:
      tags: [Nexus Cascades]
      summary: List cascade categories
      description: Returns all user-defined kanban category columns, sorted by sort_order.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Category list
          content:
            application/json:
              schema:
                type: object
                properties:
                  categories:
                    type: array
                    items:
                      type: object
                      properties:
                        id:         {type: string}
                        name:       {type: string}
                        icon:       {type: string}
                        color:      {type: string}
                        sort_order: {type: integer}
                        created:    {type: string}
                        updated:    {type: string}
                  count: {type: integer}
    post:
      tags: [Nexus Cascades]
      summary: Create cascade category
      description: Creates a new kanban column for the Cascades board.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:       {type: string}
                icon:       {type: string, default: "📁"}
                color:      {type: string, default: indigo}
                sort_order: {type: integer}
      responses:
        '201':
          description: Category created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:      {type: string}
                  message: {type: string}
        '400':
          description: Bad request — name is required

  /enaibleusovereignty/api/v1/nexus/cascade-categories/{id}:
    get:
      tags: [Nexus Cascades]
      summary: Get cascade category
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Category record
        '404':
          description: Category not found
    put:
      tags: [Nexus Cascades]
      summary: Update cascade category
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:       {type: string}
                icon:       {type: string}
                color:      {type: string}
                sort_order: {type: integer}
      responses:
        '200':
          description: Category updated
        '404':
          description: Category not found
    delete:
      tags: [Nexus Cascades]
      summary: Delete cascade category
      description: Deletes the category and moves any associated cascades to uncategorized.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Category deleted
        '404':
          description: Category not found

  /enaibleusovereignty/api/v1/nexus/cascade-categories/reorder:
    post:
      tags: [Nexus Cascades]
      summary: Bulk reorder cascade categories
      description: Accepts an ordered array of category IDs and updates sort_order for each.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [ids]
              properties:
                ids:
                  type: array
                  items: {type: string}
      responses:
        '200':
          description: Reordered

  # Nexus Webhooks — outbound destinations + inbound listener endpoints
  /enaibleusovereignty/api/v1/nexus/webhooks/outbound:
    get:
      tags: [Nexus Webhooks]
      summary: List outbound webhook destinations
      description: Returns all outbound webhook destinations with their events and status.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Destination list
          content:
            application/json:
              schema:
                type: object
                properties:
                  destinations:
                    type: array
                    items:
                      type: object
                      properties:
                        id:          {type: string}
                        name:        {type: string}
                        url:         {type: string}
                        secret:      {type: string}
                        events:      {type: string, description: "Comma-separated event types, e.g. cascade.completed,webhook.test"}
                        description: {type: string}
                        active:      {type: boolean}
                        created:     {type: string}
                        updated:     {type: string}
                  count: {type: integer}
    post:
      tags: [Nexus Webhooks]
      summary: Create outbound webhook destination
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, url]
              properties:
                name:        {type: string}
                url:         {type: string, format: uri}
                secret:      {type: string, description: "HMAC signing secret (optional)"}
                events:      {type: string, description: "Comma-separated event filter; empty = receive all"}
                description: {type: string}
                active:      {type: boolean, default: true}
      responses:
        '201':
          description: Destination created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:      {type: string}
                  success: {type: boolean}
        '400':
          description: Bad request — name and url are required

  /enaibleusovereignty/api/v1/nexus/webhooks/outbound/{id}:
    get:
      tags: [Nexus Webhooks]
      summary: Get outbound webhook destination
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Destination record
        '404':
          description: Not found
    patch:
      tags: [Nexus Webhooks]
      summary: Update outbound webhook destination
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:        {type: string}
                url:         {type: string, format: uri}
                secret:      {type: string}
                events:      {type: string}
                description: {type: string}
                active:      {type: boolean}
      responses:
        '200':
          description: Updated
        '404':
          description: Not found
    delete:
      tags: [Nexus Webhooks]
      summary: Delete outbound webhook destination
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Deleted
        '404':
          description: Not found

  /enaibleusovereignty/api/v1/nexus/webhooks/outbound/{id}/deliveries:
    get:
      tags: [Nexus Webhooks]
      summary: List delivery log for outbound webhook
      description: Returns up to 100 most recent delivery attempts for the given destination.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Delivery log
          content:
            application/json:
              schema:
                type: object
                properties:
                  deliveries:
                    type: array
                    items:
                      type: object
                      properties:
                        id:             {type: string}
                        destination_id: {type: string}
                        event:          {type: string}
                        payload:        {type: string}
                        status:         {type: string, enum: [ok, error]}
                        status_code:    {type: integer}
                        response:       {type: string}
                        attempts:       {type: integer}
                        error:          {type: string}
                        sent_at:        {type: string, format: date-time}
                  count: {type: integer}

  /enaibleusovereignty/api/v1/nexus/webhooks/outbound/{id}/test:
    post:
      tags: [Nexus Webhooks]
      summary: Fire test event to outbound webhook
      description: Queues a webhook.test event to the specified destination for connectivity testing.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Test event queued
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  message: {type: string}
        '404':
          description: Destination not found

  /enaibleusovereignty/api/v1/nexus/webhooks/inbound:
    get:
      tags: [Nexus Webhooks]
      summary: List inbound webhook endpoints
      description: Returns all configured inbound listener endpoints.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Endpoint list
          content:
            application/json:
              schema:
                type: object
                properties:
                  endpoints:
                    type: array
                    items:
                      type: object
                      properties:
                        id:            {type: string}
                        name:          {type: string}
                        slug:          {type: string}
                        secret:        {type: string}
                        description:   {type: string}
                        action_type:   {type: string, enum: [log_only, trigger_cascade, trigger_job]}
                        action_target: {type: string, description: "cascade_id or job_slug depending on action_type"}
                        active:        {type: boolean}
                        created:       {type: string}
                        updated:       {type: string}
                  count: {type: integer}
    post:
      tags: [Nexus Webhooks]
      summary: Create inbound webhook endpoint
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, slug]
              properties:
                name:          {type: string}
                slug:          {type: string, description: "Lowercase alphanumeric + hyphens, max 64 chars"}
                secret:        {type: string, description: "Optional HMAC validation secret"}
                description:   {type: string}
                action_type:   {type: string, enum: [log_only, trigger_cascade, trigger_job], default: log_only}
                action_target: {type: string, description: "cascade_id or job_slug"}
                active:        {type: boolean, default: true}
      responses:
        '201':
          description: Endpoint created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:      {type: string}
                  success: {type: boolean}
        '400':
          description: Bad request — name and slug are required, slug must be lowercase alphanumeric with hyphens

  /enaibleusovereignty/api/v1/nexus/webhooks/inbound/{id}:
    get:
      tags: [Nexus Webhooks]
      summary: Get inbound webhook endpoint
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Endpoint record
        '404':
          description: Not found
    patch:
      tags: [Nexus Webhooks]
      summary: Update inbound webhook endpoint
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:          {type: string}
                slug:          {type: string}
                secret:        {type: string}
                description:   {type: string}
                action_type:   {type: string, enum: [log_only, trigger_cascade, trigger_job]}
                action_target: {type: string}
                active:        {type: boolean}
      responses:
        '200':
          description: Updated
        '404':
          description: Not found
    delete:
      tags: [Nexus Webhooks]
      summary: Delete inbound webhook endpoint
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Deleted
        '404':
          description: Not found

  /enaibleusovereignty/api/v1/nexus/webhooks/inbound/{id}/calls:
    get:
      tags: [Nexus Webhooks]
      summary: List call log for inbound webhook endpoint
      description: Returns up to 100 most recent inbound call records for the given endpoint.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Call log
          content:
            application/json:
              schema:
                type: object
                properties:
                  calls:
                    type: array
                    items:
                      type: object
                      properties:
                        id:          {type: string}
                        endpoint_id: {type: string}
                        method:      {type: string}
                        body:        {type: string}
                        status:      {type: string, enum: [ok, error, ignored]}
                        result:      {type: string}
                        received_at: {type: string, format: date-time}
                  count: {type: integer}

  /enaibleusovereignty/api/v1/nexus/webhooks/in/{slug}:
    post:
      tags: [Nexus Webhooks]
      summary: Public inbound webhook receiver
      description: >
        Receives inbound webhook payloads from external systems. No authentication required.
        Access is controlled by the slug and optional HMAC secret in the X-Hub-Signature-256 header.
        The action configured on the endpoint (log_only, trigger_cascade, trigger_job) is executed automatically.
      parameters:
        - name: slug
          in: path
          required: true
          schema: {type: string}
        - name: X-Hub-Signature-256
          in: header
          required: false
          schema: {type: string}
          description: "HMAC-SHA256 signature of the payload (sha256=<hex>), required if endpoint has a secret set"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              description: Arbitrary JSON payload from the upstream system
      responses:
        '200':
          description: Payload accepted and processed
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  message: {type: string}
        '400':
          description: Bad request — slug missing or invalid payload
        '401':
          description: Signature mismatch
        '404':
          description: No active endpoint found for slug

  /enaibleusovereignty/api/v1/nexus/agent-tasks:
    get:
      tags: [Nexus Agent Tasks]
      summary: List agent tasks
      parameters:
        - {name: assigned_to, in: query, schema: {type: string}}
        - {name: status,      in: query, schema: {type: string, enum: [OPEN, ACTIVE, DONE, FAILED]}}
        - {name: parent_task_id, in: query, schema: {type: string}}
        - {name: type,        in: query, schema: {type: string}}
      responses:
        '200':
          description: Task list
          content:
            application/json:
              schema:
                type: object
                properties:
                  tasks: {type: array, items: {$ref: '#/components/schemas/AgentTask'}}
                  total: {type: integer}
    post:
      tags: [Nexus Agent Tasks]
      summary: Create an agent task
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, assigned_to]
              properties:
                title:       {type: string}
                description: {type: string}
                assigned_to: {type: string}
                type:        {type: string}
                payload:     {type: object, additionalProperties: true}
      responses:
        '201':
          description: Task created
          content:
            application/json:
              schema: {$ref: '#/components/schemas/AgentTask'}

  /enaibleusovereignty/api/v1/nexus/agent-tasks/{id}:
    get:
      tags: [Nexus Agent Tasks]
      summary: Get task by ID (includes children)
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Task detail
          content:
            application/json:
              schema: {$ref: '#/components/schemas/AgentTask'}
    patch:
      tags: [Nexus Agent Tasks]
      summary: Update task status or result
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status: {type: string, enum: [ACTIVE, DONE, FAILED]}
                result: {type: object, additionalProperties: true}
                reason: {type: string}
      responses:
        '200':
          description: Updated
    delete:
      tags: [Nexus Agent Tasks]
      summary: Delete an agent task
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/nexus/agent-tasks/{id}/promote:
    post:
      tags: [Nexus Agent Tasks]
      summary: Promote a completed task to the next stage
      description: >
        Stages the completed task's output as a new work-review document targeting
        one of: assessment (.agent/assessments/), research (.agent/research/), or
        work_review (.agent/work/approved/). The staged file appears in the Work
        Review UI for Steward approval before promotion.
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [target_type]
              properties:
                target_type:
                  type: string
                  enum: [assessment, research, work_review]
                  description: The document type to promote this task into
      responses:
        '200':
          description: Document staged for review
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:          {type: boolean}
                  staged_as:   {type: string}
                  target_type: {type: string}
                  target_path: {type: string}

  /enaibleusovereignty/api/v1/nexus/agent-tasks/clear-failed:
    post:
      tags: [Nexus Agent Tasks]
      summary: Delete all FAILED agent tasks
      responses:
        '200':
          description: Cleared
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: {type: boolean}
                  deleted: {type: integer}

  /enaibleusovereignty/api/v1/nexus/assessments/to-research:
    post:
      tags: [Nexus Assessments]
      summary: Promote an assessment to a research document
      description: >
        Converts an assessment report's content into a research document staged
        in .agent/work/review/ for Steward approval before being promoted to
        .agent/research/.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, content]
              properties:
                title:   {type: string, description: Assessment report title}
                content: {type: string, description: Full assessment markdown content}
      responses:
        '200':
          description: Research document staged for review
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:          {type: boolean}
                  staged_as:   {type: string}
                  target_path: {type: string}

  # ── Messenger ──────────────────────────────────────────────────────────────

  /enaibleusovereignty/api/v1/messenger/ws:
    get:
      summary: Messenger WebSocket — real-time message delivery
      tags: [Messenger]
      description: |
        Upgrade to WebSocket. Receives `message` frames for all channels the
        user is a member of. Auth via `pb_auth` cookie.
      responses:
        '101': {description: Switching Protocols}
        '401': {description: Unauthorized}

  /enaibleusovereignty/api/v1/messenger/channels:
    get:
      summary: List channels the current user belongs to
      tags: [Messenger]
      responses:
        '200':
          description: Channel list
          content:
            application/json:
              schema:
                type: object
                properties:
                  channels:
                    type: array
                    items: {$ref: '#/components/schemas/MessengerChannel'}
    post:
      summary: Create a new channel
      tags: [Messenger]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:    {type: string}
                members: {type: array, items: {type: string}, description: User IDs to add}
      responses:
        '200':
          description: Created channel
          content:
            application/json:
              schema: {$ref: '#/components/schemas/MessengerChannel'}

  /enaibleusovereignty/api/v1/messenger/channels/{id}:
    get:
      summary: Get a single channel
      tags: [Messenger]
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Channel record
          content:
            application/json:
              schema: {$ref: '#/components/schemas/MessengerChannel'}
        '403': {description: Forbidden — not a member}
        '404': {description: Not found}

  /enaibleusovereignty/api/v1/messenger/channels/{id}/messages:
    get:
      summary: List messages in a channel (decrypted)
      tags: [Messenger]
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Message list
          content:
            application/json:
              schema:
                type: object
                properties:
                  messages:
                    type: array
                    items: {$ref: '#/components/schemas/MessengerMessage'}
    post:
      summary: Send a message to a channel
      tags: [Messenger]
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [body]
              properties:
                body:     {type: string, description: Plaintext message body}
                mentions: {type: array, items: {type: string}, description: Mentioned user IDs}
      responses:
        '200':
          description: Created message (plaintext)
          content:
            application/json:
              schema: {$ref: '#/components/schemas/MessengerMessage'}

  /enaibleusovereignty/api/v1/messenger/dm:
    post:
      summary: Get or create a DM channel between the current user and a target
      tags: [Messenger]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [target_id]
              properties:
                target_id: {type: string, description: Target user ID}
      responses:
        '200':
          description: Existing or newly created DM channel
          content:
            application/json:
              schema: {$ref: '#/components/schemas/MessengerChannel'}

  /enaibleusovereignty/api/v1/messenger/users:
    get:
      summary: List users available for @mention and DM
      tags: [Messenger]
      responses:
        '200':
          description: User list (id, email, name only — no sensitive fields)
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items: {$ref: '#/components/schemas/MessengerUser'}

  # Messenger — Presence
  /enaibleusovereignty/api/v1/messenger/presence:
    get:
      summary: Get online presence map
      tags: [Messenger]
      description: Returns the presence (online/offline) state for all users visible to the caller.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Presence map

  # Auth — 2FA Verify (pre-session MFA step)
  /enaibleusovereignty/api/v1/auth/2fa/verify:
    post:
      summary: Verify 2FA TOTP code after password login
      description: Called after a successful password login when the account has TOTP enabled. Provides the 6-digit code to exchange the temporary MFA token for a full session.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token, code]
              properties:
                token: {type: string, description: Temporary MFA token returned by /auth/login}
                code:  {type: string, description: 6-digit TOTP code}
      responses:
        '200':
          description: Session created
        '401':
          description: Invalid or expired token / wrong TOTP code

  # 2FA — TOTP management
  /enaibleusovereignty/api/v1/2fa/status:
    get:
      summary: Get 2FA status for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: 2FA status

  /enaibleusovereignty/api/v1/2fa/setup/start:
    post:
      summary: Start 2FA TOTP setup — returns provisioning URI and QR seed
      security:
        - cookieAuth: []
      responses:
        '200':
          description: TOTP provisioning URI

  /enaibleusovereignty/api/v1/2fa/setup/confirm:
    post:
      summary: Confirm 2FA TOTP setup with a valid code
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code]
              properties:
                code: {type: string, description: 6-digit TOTP code to confirm setup}
      responses:
        '200':
          description: 2FA enabled

  /enaibleusovereignty/api/v1/2fa/disable:
    post:
      summary: Disable 2FA for current user
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code]
              properties:
                code: {type: string, description: Current TOTP code to confirm disable}
      responses:
        '200':
          description: 2FA disabled

  # GDPR — Data Rights
  /enaibleusovereignty/api/v1/gdpr/export:
    get:
      summary: Export all personal data for the current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: JSON export of all user data

  /enaibleusovereignty/api/v1/gdpr/delete:
    post:
      summary: Request account and data deletion
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Deletion request queued

  # Security — Audit & Sessions (via SecurityHandler)
  /enaibleusovereignty/api/v1/security/overview:
    get:
      summary: Get security overview dashboard
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Security overview

  /enaibleusovereignty/api/v1/security/audit-log:
    get:
      summary: Get security audit log entries
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
        - {name: filter,  in: query, schema: {type: string}}
        - {name: sort,    in: query, schema: {type: string}}
      responses:
        '200':
          description: Audit log entries

  /enaibleusovereignty/api/v1/security/sessions:
    get:
      summary: List active sessions for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Active session list

  /enaibleusovereignty/api/v1/security/sessions/revoke:
    post:
      summary: Revoke a session
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [session_id]
              properties:
                session_id: {type: string}
      responses:
        '200':
          description: Session revoked

  # Security — Intrusion Detection
  /enaibleusovereignty/api/v1/security/probes:
    get:
      summary: List recorded intrusion probes
      security:
        - cookieAuth: []
      parameters:
        - {name: limit,  in: query, schema: {type: integer}}
        - {name: offset, in: query, schema: {type: integer}}
      responses:
        '200':
          description: Probe list

  /enaibleusovereignty/api/v1/security/probes/stats:
    get:
      summary: Get intrusion probe statistics
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Probe stats

  /enaibleusovereignty/api/v1/security/patterns:
    get:
      summary: List custom intrusion detection patterns
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Pattern list

  /enaibleusovereignty/api/v1/security/patterns/reload:
    post:
      summary: Reload custom intrusion detection patterns from disk
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Patterns reloaded

  /enaibleusovereignty/api/v1/security/retry-police-reports:
    post:
      summary: Retry failed police report deliveries
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Retry result

  # Agent Loops — Heartbeat
  /enaibleusovereignty/api/v1/agent-loops:
    get:
      summary: List agent loops
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Loop list
    post:
      summary: Register or update an agent loop
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:     {type: string}
                interval: {type: string}
                enabled:  {type: boolean}
      responses:
        '200':
          description: Loop registered

  /enaibleusovereignty/api/v1/agent-loops/delete:
    post:
      summary: Delete an agent loop
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Loop deleted

  /enaibleusovereignty/api/v1/agent-loops/fire:
    post:
      summary: Fire an agent loop immediately
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Loop fired

  # Archivist — Memory Consolidation
  /enaibleusovereignty/api/v1/archivist/run:
    post:
      summary: Trigger archivist memory consolidation run
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Consolidation started

  /enaibleusovereignty/api/v1/archivist/status:
    get:
      summary: Get archivist status
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Archivist status

  # Nexus Cascades — CRUD + Run + Runs
  /enaibleusovereignty/api/v1/nexus/cascades:
    get:
      tags: [Nexus Cascades]
      summary: List all cascades
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Cascade list with enriched schedule data
    post:
      tags: [Nexus Cascades]
      summary: Create a new cascade
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, definition]
              properties:
                name:       {type: string}
                icon:       {type: string}
                definition: {type: string, description: YAML cascade definition}
                status:     {type: string, enum: [ACTIVE, PAUSED]}
      responses:
        '201':
          description: Cascade created

  /enaibleusovereignty/api/v1/nexus/cascades/{id}:
    get:
      tags: [Nexus Cascades]
      summary: Get a single cascade
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Cascade record
        '404':
          description: Not found
    put:
      tags: [Nexus Cascades]
      summary: Update a cascade definition
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:       {type: string}
                icon:       {type: string}
                definition: {type: string}
                status:     {type: string, enum: [ACTIVE, PAUSED]}
      responses:
        '200':
          description: Updated
    delete:
      tags: [Nexus Cascades]
      summary: Delete a cascade
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/nexus/cascades/{id}/run:
    post:
      tags: [Nexus Cascades]
      summary: Trigger a cascade run manually
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              description: Optional input parameters for the cascade
      responses:
        '200':
          description: Run started
          content:
            application/json:
              schema:
                type: object
                properties:
                  run_id: {type: string}
                  status: {type: string}

  /enaibleusovereignty/api/v1/nexus/cascades/{id}/runs:
    get:
      tags: [Nexus Cascades]
      summary: List run history for a cascade
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id,    in: path,  required: true,  schema: {type: string}}
        - {name: limit, in: query, required: false, schema: {type: integer}}
      responses:
        '200':
          description: Run history

  /enaibleusovereignty/api/v1/nexus/cascades/{id}/category:
    patch:
      tags: [Nexus Cascades]
      summary: Assign cascade to a category
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                category_id: {type: string, description: "Category ID or empty string to uncategorize"}
      responses:
        '200':
          description: Category assigned

  /enaibleusovereignty/api/v1/nexus/cascades/runs/active:
    get:
      tags: [Nexus Cascades]
      summary: List all currently in-flight cascade runs
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Active run list

  /enaibleusovereignty/api/v1/nexus/cascades/runs/cleanup:
    post:
      tags: [Nexus Cascades]
      summary: Mark stale running/pending runs as timed_out
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Cleanup result

  /enaibleusovereignty/api/v1/nexus/cascades/runs/stats:
    get:
      tags: [Nexus Cascades]
      summary: Get today's cascade run counts for the dashboard
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Run stats

  /enaibleusovereignty/api/v1/nexus/cascades/runs/{runId}:
    get:
      tags: [Nexus Cascades]
      summary: Get a single cascade run with parsed step results
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: runId, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Run detail

  /enaibleusovereignty/api/v1/nexus/cascades/runs/{runId}/notes:
    patch:
      tags: [Nexus Cascades]
      summary: Update notes on a cascade run
      security:
        - cookieAuth: []
      parameters:
        - {name: runId, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [notes]
              properties:
                notes: {type: string}
      responses:
        '200':
          description: Notes updated

  # Admin — Cascade Deduplicate
  /enaibleusovereignty/api/v1/admin/cascades/deduplicate:
    post:
      summary: Trigger cascade deduplication immediately
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Deduplication result

  # Admin — Memory Encryption Migration
  /enaibleusovereignty/api/v1/admin/migrate/encrypt-memories:
    post:
      summary: Encrypt all legacy plaintext memories (one-time migration)
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Migration result
          content:
            application/json:
              schema:
                type: object
                properties:
                  migrated: {type: integer}
                  skipped:  {type: integer}
                  errors:   {type: array, items: {type: string}}
                  message:  {type: string}

  # Admin — Buddy Art Queue
  /enaibleusovereignty/api/v1/admin/buddy/art-queue:
    get:
      summary: Get buddy art generation queue
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Queue items

  /enaibleusovereignty/api/v1/admin/buddy/art-queue/seed:
    post:
      summary: Seed buddy art queue with missing layer variants
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Seeded

  /enaibleusovereignty/api/v1/admin/buddy/art-queue/retry:
    post:
      summary: Retry failed buddy art generation tasks
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Retried

  /enaibleusovereignty/api/v1/admin/buddy/generate-layer:
    post:
      summary: Generate a specific buddy layer image
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                layer: {type: string}
                variant: {type: string}
      responses:
        '200':
          description: Layer generated

  /enaibleusovereignty/api/v1/admin/buddy/generate-all:
    post:
      summary: Generate all missing buddy layer images
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Generation started

  # Admin — Subscriptions
  /enaibleusovereignty/api/v1/admin/subscriptions:
    get:
      summary: List all subscriptions (admin)
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Subscription list

  /enaibleusovereignty/api/v1/admin/subscriptions/{userID}/cancel:
    post:
      summary: Cancel a user's subscription (admin)
      security:
        - cookieAuth: []
      parameters:
        - {name: userID, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Subscription cancelled

  # Buddy — AI GACHA Companion
  /enaibleusovereignty/api/v1/buddy/me:
    get:
      summary: Get current user's buddy
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Buddy record

  /enaibleusovereignty/api/v1/buddy/link:
    post:
      summary: Link a buddy to current user's AI mail account
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                buddy_id: {type: string}
      responses:
        '200':
          description: Buddy linked

  /enaibleusovereignty/api/v1/buddy/xp:
    post:
      summary: Award XP to current user's buddy
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [xp]
              properties:
                xp:     {type: integer}
                reason: {type: string}
      responses:
        '200':
          description: XP awarded

  # Buddy gameplay — abilities, accessories, chat, missions, thoughts, art
  /enaibleusovereignty/api/v1/buddy/abilities:
    get:
      summary: List all buddy abilities with unlock status for the current buddy
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Abilities with unlock state

  /enaibleusovereignty/api/v1/buddy/accessories:
    get:
      summary: List all buddy accessories with ownership/equip status
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Accessories list

  /enaibleusovereignty/api/v1/buddy/chat:
    post:
      summary: Send a chat message to the current user's buddy
      tags: [Buddy]
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [message]
              properties:
                message: {type: string}
      responses:
        '200':
          description: Buddy reply

  /enaibleusovereignty/api/v1/buddy/chat/history:
    get:
      summary: Get the buddy chat history for the current user
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Chat history

  /enaibleusovereignty/api/v1/buddy/missions:
    get:
      summary: List available buddy missions
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Missions list

  /enaibleusovereignty/api/v1/buddy/missions/active:
    get:
      summary: List the current buddy's active (in-progress) missions
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Active missions

  /enaibleusovereignty/api/v1/buddy/missions/{missionID}/dispatch:
    post:
      summary: Dispatch the buddy on a mission
      tags: [Buddy]
      security:
        - cookieAuth: []
      parameters:
        - {name: missionID, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Mission dispatched

  /enaibleusovereignty/api/v1/buddy/active-missions/{activeID}/claim:
    post:
      summary: Claim the rewards of a completed active mission
      tags: [Buddy]
      security:
        - cookieAuth: []
      parameters:
        - {name: activeID, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Rewards claimed

  /enaibleusovereignty/api/v1/buddy/thoughts:
    get:
      summary: List the buddy's generated thoughts
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Thoughts list

  /enaibleusovereignty/api/v1/buddy/thoughts/generate:
    post:
      summary: Manually trigger generation of a new buddy thought
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Thought generated

  /enaibleusovereignty/api/v1/buddy/regenerate-art:
    post:
      summary: Regenerate the current buddy's creature art
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Art regeneration queued

  /enaibleusovereignty/api/v1/buddy/creature-image:
    get:
      summary: Get the current buddy's creature image
      tags: [Buddy]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Creature image (served from persistence)

  # Nexus Kill Switch
  /enaibleusovereignty/api/v1/nexus/kill-switch/status:
    get:
      summary: Get kill switch status
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Kill switch status (halted or running)

  /enaibleusovereignty/api/v1/nexus/kill-switch/halt:
    post:
      summary: Halt the entire AI workforce
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Workforce halted

  /enaibleusovereignty/api/v1/nexus/kill-switch/resume:
    post:
      summary: Resume the AI workforce after halt
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Workforce resumed

  # Nexus Imagery
  /enaibleusovereignty/api/v1/nexus/imagery/recognize:
    post:
      summary: Analyse an image with AI vision (NVIDIA NIM)
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:    {type: string, description: Image URL to analyse}
                prompt: {type: string, description: Optional vision prompt}
      responses:
        '200':
          description: Recognition result

  /enaibleusovereignty/api/v1/nexus/imagery/generate:
    post:
      summary: Generate an image with AI (NVIDIA NIM)
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [prompt]
              properties:
                prompt: {type: string}
                model:  {type: string}
                width:  {type: integer}
                height: {type: integer}
      responses:
        '200':
          description: Generated image URL

  /enaibleusovereignty/api/v1/nexus/imagery/recognitions:
    get:
      summary: List image recognition results
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Recognition list

  /enaibleusovereignty/api/v1/nexus/imagery/generated:
    get:
      summary: List generated images
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Generated image list

  /enaibleusovereignty/api/v1/nexus/imagery/models:
    get:
      summary: List available imagery models
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Model list

  /enaibleusovereignty/api/v1/nexus/imagery/recognitions/{id}:
    get:
      summary: Get a single recognition result
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Recognition detail

  /enaibleusovereignty/api/v1/nexus/imagery/generated/{id}:
    get:
      summary: Get a single generated image record
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Generated image detail

  # Nexus Notes
  /enaibleusovereignty/api/v1/nexus/notes:
    get:
      summary: List brain notes
      security:
        - cookieAuth: []
      parameters:
        - {name: type,   in: query, schema: {type: string}}
        - {name: agent,  in: query, schema: {type: string}}
        - {name: limit,  in: query, schema: {type: integer}}
        - {name: offset, in: query, schema: {type: integer}}
      responses:
        '200':
          description: Note list
    post:
      summary: Create a brain note
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content:  {type: string}
                type:     {type: string, enum: [note, idea, reminder, task]}
                agent_id: {type: string}
                tags:     {type: array, items: {type: string}}
      responses:
        '201':
          description: Note created

  /enaibleusovereignty/api/v1/nexus/notes/{id}:
    get:
      summary: Get a single note
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Note record
        '404':
          description: Not found
    patch:
      summary: Update a note
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                content: {type: string}
                type:    {type: string}
                tags:    {type: array, items: {type: string}}
      responses:
        '200':
          description: Note updated
    delete:
      summary: Delete a note
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/nexus/notes/{id}/convert-todo:
    post:
      summary: Convert a note to a Sentinel todo
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Todo created

  /enaibleusovereignty/api/v1/nexus/notes/{id}/convert-memory:
    post:
      summary: Convert a note to an enhanced memory
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Memory created

  # Nexus KV Store
  /enaibleusovereignty/api/v1/nexus/kv:
    get:
      summary: List KV store entries
      security:
        - cookieAuth: []
      parameters:
        - {name: access_level, in: query, schema: {type: string, enum: [private, shared, global]}}
        - {name: prefix,       in: query, schema: {type: string}}
      responses:
        '200':
          description: KV entries
    post:
      summary: Create a KV entry
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [key, value]
              properties:
                key:          {type: string}
                value:        {}
                access_level: {type: string, enum: [private, shared, global], default: private}
                ttl:          {type: integer, description: TTL in seconds (0 = never expires)}
      responses:
        '201':
          description: Entry created

  /enaibleusovereignty/api/v1/nexus/kv/{id}:
    put:
      summary: Update a KV entry
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                value:        {}
                access_level: {type: string}
                ttl:          {type: integer}
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a KV entry
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Nexus Audit Log
  /enaibleusovereignty/api/v1/nexus/audit-log:
    get:
      summary: List enaibleu audit log entries
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
        - {name: filter,  in: query, schema: {type: string}}
        - {name: sort,    in: query, schema: {type: string}}
      responses:
        '200':
          description: Audit log entries

  /enaibleusovereignty/api/v1/nexus/audit-log/stats:
    get:
      summary: Get audit log statistics
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Audit stats

  # Nexus Agent States
  /enaibleusovereignty/api/v1/nexus/agent-states:
    get:
      summary: List agent states (activity sidebar)
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Agent state list

  # Nexus Analytics
  /enaibleusovereignty/api/v1/nexus/analytics:
    get:
      summary: Get Nexus usage analytics
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Analytics data

  # Nexus Protocol Health
  /enaibleusovereignty/api/v1/nexus/protocol-health:
    get:
      summary: Scan governance files for protocol health
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Protocol health report

  # Nexus Audit — LLM Protocol Assessment
  /enaibleusovereignty/api/v1/nexus/audit/reports:
    get:
      summary: List LLM audit reports
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
      responses:
        '200':
          description: Audit report list

  /enaibleusovereignty/api/v1/nexus/audit/reports/{id}:
    get:
      summary: Get a single audit report
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Audit report
    delete:
      summary: Delete an audit report
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/nexus/audit/enrichments:
    get:
      summary: List enrichment queue items
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Enrichment list

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}:
    get:
      summary: Get a single enrichment item
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Enrichment item

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}/approve:
    post:
      summary: Approve an enrichment proposal
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Approved

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}/reject:
    post:
      summary: Reject an enrichment proposal
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Rejected

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}/force:
    post:
      summary: Force-apply an enrichment proposal without review
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Applied

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}/retry:
    post:
      summary: Retry a failed enrichment
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Retried

  /enaibleusovereignty/api/v1/nexus/audit/enrichments/{id}/preview:
    get:
      summary: Preview enrichment changes before applying
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Preview diff

  /enaibleusovereignty/api/v1/nexus/audit/trigger:
    post:
      summary: Trigger a full protocol audit run
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Audit started

  /enaibleusovereignty/api/v1/nexus/audit/stop:
    post:
      summary: Stop a running audit
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Audit stopped

  /enaibleusovereignty/api/v1/nexus/audit/status:
    get:
      summary: Get current audit run status
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Audit status

  /enaibleusovereignty/api/v1/nexus/audit/settings:
    get:
      summary: Get audit settings
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Audit settings
    post:
      summary: Update audit settings
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Settings updated

  # Nexus Work Review
  /enaibleusovereignty/api/v1/nexus/work/review:
    get:
      summary: List staged work review files
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Work review list

  /enaibleusovereignty/api/v1/nexus/work/review/file:
    get:
      summary: Get a work review file's content
      security:
        - cookieAuth: []
      parameters:
        - {name: path, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: File content

  /enaibleusovereignty/api/v1/nexus/work/review/diff:
    get:
      summary: Get a diff for a work review file
      security:
        - cookieAuth: []
      parameters:
        - {name: path, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: Unified diff

  /enaibleusovereignty/api/v1/nexus/work/review/approve:
    post:
      summary: Approve and promote a work review file
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [path]
              properties:
                path: {type: string}
      responses:
        '200':
          description: File promoted

  /enaibleusovereignty/api/v1/nexus/work/review/reject:
    post:
      summary: Reject and delete a work review file
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [path]
              properties:
                path:   {type: string}
                reason: {type: string}
      responses:
        '200':
          description: File rejected

  # Nexus Assessment
  /enaibleusovereignty/api/v1/nexus/work/feedback:
    post:
      summary: Submit feedback on a work output
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [work_id, feedback]
              properties:
                work_id:  {type: string}
                feedback: {type: string}
                score:    {type: integer, minimum: 1, maximum: 5}
      responses:
        '200':
          description: Feedback recorded

  /enaibleusovereignty/api/v1/nexus/work/governance/override:
    post:
      summary: Override a governance violation flag on a work output
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [work_id, justification]
              properties:
                work_id:       {type: string}
                justification: {type: string}
      responses:
        '200':
          description: Override applied

  /enaibleusovereignty/api/v1/nexus/assessments/config:
    get:
      summary: Get assessor configuration
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Assessor config
    post:
      summary: Update assessor configuration
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Config updated

  /enaibleusovereignty/api/v1/nexus/assessments/proposals/apply:
    post:
      summary: Apply pending assessment proposals to .agent/ files
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                ids: {type: array, items: {type: string}, description: "Optional list of proposal IDs; omit to apply all pending"}
      responses:
        '200':
          description: Proposals applied

  # Nexus Rewards — Missing
  /enaibleusovereignty/api/v1/nexus/rewards/work/dismiss:
    post:
      summary: Dismiss a work output from the review feed
      security:
        - cookieAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                work_id: {type: string}
      responses:
        '200':
          description: Dismissed

  # Nexus PII — Personal Data Detection
  /enaibleusovereignty/api/v1/nexus/personal-data/detect:
    post:
      summary: Detect PII entities in text using GLiNER
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text]
              properties:
                text:       {type: string}
                threshold:  {type: number, default: 0.5, description: "Confidence threshold (0–1)"}
                entity_types:
                  type: array
                  items: {type: string}
                  description: "Entity types to detect (default: all)"
      responses:
        '200':
          description: PII detection result

  /enaibleusovereignty/api/v1/nexus/personal-data/findings:
    get:
      summary: List stored PII findings
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
      responses:
        '200':
          description: Finding list

  /enaibleusovereignty/api/v1/nexus/personal-data/findings/{id}:
    get:
      summary: Get a single PII finding
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Finding detail
    delete:
      summary: Delete a PII finding
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/nexus/personal-data/stats:
    get:
      summary: Get PII detection statistics
      security:
        - cookieAuth: []
      responses:
        '200':
          description: PII stats

  # Sentinel — Reminders
  /enaibleusovereignty/api/v1/sentinel/reminders:
    get:
      summary: List reminders
      security:
        - cookieAuth: []
      parameters:
        - {name: user_id,  in: query, schema: {type: string}}
        - {name: status,   in: query, schema: {type: string}}
        - {name: upcoming, in: query, schema: {type: boolean}}
      responses:
        '200':
          description: Reminder list
    post:
      summary: Create a reminder
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, remind_at]
              properties:
                title:     {type: string}
                body:      {type: string}
                remind_at: {type: string, format: date-time}
                user_id:   {type: string}
      responses:
        '201':
          description: Reminder created

  /enaibleusovereignty/api/v1/sentinel/reminders/{id}:
    get:
      summary: Get a reminder
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Reminder record
    put:
      summary: Update a reminder
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a reminder
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Sentinel — Schedules (household weekly schedule)
  /enaibleusovereignty/api/v1/sentinel/schedules:
    get:
      summary: List schedule blocks (household-scoped)
      description: >
        Returns the household's schedule blocks. Scoped to the authenticated
        user; household members (owner + partner) see the shared set, admins
        see all.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Schedule list
    post:
      summary: Create a schedule block
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScheduleItem'
      responses:
        '200':
          description: Schedule created

  /enaibleusovereignty/api/v1/sentinel/schedules/{id}:
    get:
      summary: Get a schedule block
      description: 404 if the block isn't owned by the caller / household (IDOR guard).
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200': {description: Schedule record}
        '404': {description: Not found / not accessible}
    put:
      summary: Update a schedule block
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScheduleItem'
      responses:
        '200': {description: Updated}
        '404': {description: Not found / not accessible}
    patch:
      summary: Update a schedule block (partial)
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScheduleItem'
      responses:
        '200': {description: Updated}
    delete:
      summary: Delete a schedule block
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200': {description: Deleted}
        '404': {description: Not found / not accessible}

  /enaibleusovereignty/api/v1/sentinel/schedules/summarize-to-discord:
    post:
      summary: Post a 7-day schedule overview to the Discord alerts channel
      security:
        - cookieAuth: []
      responses:
        '200': {description: Posted; returns the rendered markdown preview}
        '502': {description: Discord post failed}

  # Bot proxy (X-API-Key) — read-only schedule access for the Discord bot
  /enaibleusovereignty/api/v1/bot/schedule/summary:
    get:
      summary: Markdown overview of the next 7 days (bot)
      security:
        - ApiKeyAuth: []
      responses:
        '200': {description: "{ markdown: string }"}
  /enaibleusovereignty/api/v1/bot/schedule/list:
    get:
      summary: Filtered household schedule blocks (bot)
      security:
        - ApiKeyAuth: []
      parameters:
        - {name: tag,         in: query, schema: {type: string}, description: "Family tag: adelita|vivian|asher|alyssia|seleena"}
        - {name: day_of_week, in: query, schema: {type: integer, minimum: 0, maximum: 6}}
        - {name: active_only, in: query, schema: {type: boolean}}
        - {name: notify_only, in: query, schema: {type: boolean}}
        - {name: search,      in: query, schema: {type: string}}
        - {name: limit,       in: query, schema: {type: integer, default: 50, maximum: 200}}
      responses:
        '200': {description: "{ items: ScheduleItem[], count: int }"}

  # Sentinel — Ideas
  /enaibleusovereignty/api/v1/sentinel/ideas:
    get:
      summary: List ideas
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Idea list
    post:
      summary: Create an idea
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title:       {type: string}
                description: {type: string}
                tags:        {type: array, items: {type: string}}
      responses:
        '201':
          description: Idea created

  /enaibleusovereignty/api/v1/sentinel/ideas/{id}:
    get:
      summary: Get an idea
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Idea record
    put:
      summary: Update an idea
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete an idea
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Sentinel — Projects
  /enaibleusovereignty/api/v1/sentinel/projects:
    get:
      summary: List projects
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Project list
    post:
      summary: Create a project
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:        {type: string}
                description: {type: string}
                status:      {type: string}
                color:       {type: string}
      responses:
        '201':
          description: Project created

  /enaibleusovereignty/api/v1/sentinel/projects/{id}:
    get:
      summary: Get a project
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Project record
    put:
      summary: Update a project
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a project
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Sentinel — CRM
  /enaibleusovereignty/api/v1/sentinel/crm/contacts:
    get:
      summary: List CRM contacts
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
        - {name: filter,  in: query, schema: {type: string}}
        - {name: sort,    in: query, schema: {type: string}}
      responses:
        '200':
          description: Contact list
    post:
      summary: Create a CRM contact
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:       {type: string}
                email:      {type: string}
                company_id: {type: string}
                phone:      {type: string}
                notes:      {type: string}
      responses:
        '201':
          description: Contact created

  /enaibleusovereignty/api/v1/sentinel/crm/contacts/{id}:
    get:
      summary: Get a CRM contact
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Contact record
    put:
      summary: Update a CRM contact
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a CRM contact
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/sentinel/crm/companies:
    get:
      summary: List CRM companies
      security:
        - cookieAuth: []
      parameters:
        - {name: page,    in: query, schema: {type: integer}}
        - {name: perPage, in: query, schema: {type: integer}}
        - {name: filter,  in: query, schema: {type: string}}
      responses:
        '200':
          description: Company list
    post:
      summary: Create a CRM company
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:    {type: string}
                domain:  {type: string}
                notes:   {type: string}
      responses:
        '201':
          description: Company created

  /enaibleusovereignty/api/v1/sentinel/crm/companies/{id}:
    get:
      summary: Get a CRM company
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Company record
    put:
      summary: Update a CRM company
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a CRM company
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Sentinel — Heatmap
  /enaibleusovereignty/api/v1/sentinel/heatmap/sites:
    get:
      summary: List heatmap-tracked sites
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Site list
    post:
      summary: Register a site for heatmap tracking
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:  {type: string}
                name: {type: string}
      responses:
        '201':
          description: Site registered

  /enaibleusovereignty/api/v1/sentinel/heatmap/sites/{id}:
    get:
      summary: Get a heatmap site
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Site record
    put:
      summary: Update a heatmap site
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a heatmap site
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/sentinel/heatmap/snippet/{id}:
    get:
      summary: Get the tracking JavaScript snippet for a site
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: JS tracking snippet

  /enaibleusovereignty/api/v1/sentinel/heatmap/beacon:
    post:
      summary: Receive a heatmap beacon event (public, no auth)
      description: Receives click/scroll events from the injected JS tracker. No authentication required.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [site_id, event_type]
              properties:
                site_id:    {type: string}
                event_type: {type: string, enum: [click, scroll, pageview]}
                x:          {type: number}
                y:          {type: number}
                page:       {type: string}
                session_id: {type: string}
      responses:
        '200':
          description: Event recorded

  /enaibleusovereignty/api/v1/sentinel/heatmap/pages:
    get:
      summary: List heatmap pages with aggregated data
      security:
        - cookieAuth: []
      parameters:
        - {name: site_id, in: query, required: true, schema: {type: string}}
        - {name: page,    in: query, schema: {type: string}}
      responses:
        '200':
          description: Page heatmap data

  /enaibleusovereignty/api/v1/sentinel/heatmap/sessions:
    get:
      summary: List heatmap session recordings
      security:
        - cookieAuth: []
      parameters:
        - {name: site_id, in: query, required: true, schema: {type: string}}
        - {name: limit,   in: query, schema: {type: integer}}
      responses:
        '200':
          description: Session list

  /enaibleusovereignty/api/v1/sentinel/heatmap/tracked-pages:
    get:
      summary: List all tracked pages for a site
      security:
        - cookieAuth: []
      parameters:
        - {name: site_id, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: Tracked page list

  /enaibleusovereignty/api/v1/sentinel/heatmap/weekly-report:
    get:
      summary: Get weekly heatmap analytics report
      security:
        - cookieAuth: []
      parameters:
        - {name: site_id, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: Weekly report

  # Sentinel — MEDDPICC additional
  /enaibleusovereignty/api/v1/sentinel/deals/reanalyze-stale:
    post:
      summary: Re-analyze all stale deals automatically
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Stale deals queued for re-analysis

  /enaibleusovereignty/api/v1/sentinel/deals/health-report:
    get:
      summary: Get MEDDPICC pipeline health report
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Pipeline health summary

  # Sentinel — LLM Config
  /enaibleusovereignty/api/v1/sentinel/llm/config:
    get:
      summary: Get BYOK LLM config for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: LLM config
    post:
      summary: Update BYOK LLM config
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                provider:    {type: string}
                api_key:     {type: string}
                model:       {type: string}
                temperature: {type: number}
      responses:
        '200':
          description: Config updated

  /enaibleusovereignty/api/v1/sentinel/llm/usage:
    get:
      summary: Get LLM usage dashboard for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Usage data

  # Sentinel — AI Model Collections (item routes)
  /enaibleusovereignty/api/v1/sentinel/ai-collections/{id}:
    get:
      summary: AI Model Hub — Get Collection
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Collection detail
    put:
      summary: AI Model Hub — Update Collection
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: AI Model Hub — Delete Collection
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # Memory Timeline, Duplicates, Merge, Digest
  /enaibleusovereignty/api/v1/memory/timeline:
    get:
      summary: Get memory timeline
      security:
        - cookieAuth: []
      parameters:
        - {name: source,   in: query, schema: {type: string, enum: [chat, explicit, enrichment, all]}}
        - {name: category, in: query, schema: {type: string}}
        - {name: days,     in: query, schema: {type: integer}}
        - {name: limit,    in: query, schema: {type: integer}}
      responses:
        '200':
          description: Timeline entries

  /enaibleusovereignty/api/v1/memory/duplicates:
    get:
      summary: Detect duplicate memories
      security:
        - cookieAuth: []
      parameters:
        - {name: threshold, in: query, schema: {type: number}}
        - {name: limit,     in: query, schema: {type: integer}}
      responses:
        '200':
          description: Duplicate groups

  /enaibleusovereignty/api/v1/memory/merge:
    post:
      summary: Merge duplicate memories
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [ids]
              properties:
                ids:         {type: array, items: {type: string}, description: "IDs of memories to merge"}
                keep_id:     {type: string, description: "Optional ID of the memory to keep (others deleted)"}
      responses:
        '200':
          description: Merge result

  /enaibleusovereignty/api/v1/memory/digest:
    post:
      summary: Generate a memory digest summary
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                category: {type: string}
                days:     {type: integer}
                limit:    {type: integer}
      responses:
        '200':
          description: Digest summary

  # Pipelines
  /enaibleusovereignty/api/v1/pipelines:
    get:
      summary: List agent pipelines
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: Pipeline list
    post:
      summary: Create a pipeline
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, steps]
              properties:
                name:  {type: string}
                steps: {type: array, items: {type: object}}
      responses:
        '201':
          description: Pipeline created

  /enaibleusovereignty/api/v1/pipelines/{id}:
    get:
      summary: Get a pipeline
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Pipeline record
    put:
      summary: Update a pipeline
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a pipeline
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted
    post:
      summary: Execute a pipeline
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              description: Optional input parameters for the pipeline
      responses:
        '200':
          description: Pipeline execution result

  # Spectre — Search
  /enaibleusovereignty/api/v1/spectre/search:
    post:
      summary: Spectre Search — Tavily-style clean search for LLM RAG
      description: Searches the web and returns clean, structured results suitable for LLM context injection. Pro session or API key required.
      security:
        - cookieAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query:       {type: string}
                max_results: {type: integer, default: 5}
                include_raw: {type: boolean, default: false}
      responses:
        '200':
          description: Search results

  # Spectre — Batch
  /enaibleusovereignty/api/v1/spectre/batch:
    post:
      summary: Spectre Batch — Submit async batch scraping job
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [urls]
              properties:
                urls:
                  type: array
                  items: {type: string}
                  description: URLs to scrape in batch
                max_concurrency: {type: integer, default: 5}
      responses:
        '200':
          description: Batch job submitted

  /enaibleusovereignty/api/v1/spectre/batch/status:
    get:
      summary: Spectre Batch — Get job status
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: Batch job status

  /enaibleusovereignty/api/v1/spectre/batch/list:
    get:
      summary: Spectre Batch — List batch jobs
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Batch job list

  # Spectre — Watch (Change Detection)
  /enaibleusovereignty/api/v1/spectre/watch:
    get:
      summary: List watched URLs for change detection
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Watch list
    post:
      summary: Add a URL to the watch list
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:       {type: string}
                interval:  {type: string, description: Check interval (e.g. 1h, 24h)}
                selector:  {type: string, description: Optional CSS selector to monitor}
                threshold: {type: number, description: Change sensitivity (0–1)}
      responses:
        '201':
          description: Watch added

  /enaibleusovereignty/api/v1/spectre/watch/detail:
    get:
      summary: Get watch entry details
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: query, required: true, schema: {type: string}}
      responses:
        '200':
          description: Watch detail

  /enaibleusovereignty/api/v1/spectre/watch/delete:
    post:
      summary: Delete a watch entry
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/spectre/watch/pause:
    post:
      summary: Pause a watch entry
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Paused

  /enaibleusovereignty/api/v1/spectre/watch/resume:
    post:
      summary: Resume a paused watch entry
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Resumed

  /enaibleusovereignty/api/v1/spectre/watch/check:
    post:
      summary: Trigger an immediate check for a watch entry
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: string}
      responses:
        '200':
          description: Check triggered

  # Spectre — Convert
  /enaibleusovereignty/api/v1/spectre/convert:
    post:
      summary: Convert document between formats (HTML, Markdown, PDF, DOCX)
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content, from, to]
              properties:
                content: {type: string}
                from:    {type: string, enum: [html, md, pdf, docx, txt]}
                to:      {type: string, enum: [html, md, pdf, docx, txt]}
          multipart/form-data:
            schema:
              type: object
              properties:
                file: {type: string, format: binary}
                from: {type: string}
                to:   {type: string}
      responses:
        '200':
          description: Converted document

  /enaibleusovereignty/api/v1/spectre/convert/formats:
    get:
      summary: List supported conversion formats
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Supported format pairs

  # Spectre — Schema Extract
  /enaibleusovereignty/api/v1/spectre/extract/schema:
    post:
      summary: Spectre Extract — LLM-guided structured data extraction
      description: Extracts structured data from a URL using an LLM with a user-defined schema. Pro session required.
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url, schema]
              properties:
                url:    {type: string}
                schema: {type: object, additionalProperties: true, description: JSON schema defining the structure to extract}
                prompt: {type: string, description: Optional extraction instructions}
      responses:
        '200':
          description: Extracted structured data

  # Spectre — CVE Enrich
  /enaibleusovereignty/api/v1/spectre/cve/entries:
    get:
      summary: List CVE intelligence entries
      security:
        - cookieAuth: []
      parameters:
        - {name: severity, in: query, schema: {type: string, enum: [critical, high, medium, low]}}
        - {name: page,     in: query, schema: {type: integer}}
        - {name: perPage,  in: query, schema: {type: integer}}
      responses:
        '200':
          description: CVE entries

  /enaibleusovereignty/api/v1/spectre/cve/enrich:
    post:
      summary: Enrich existing CVE entries with AI analysis
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                id:    {type: string, description: "Optional CVE entry ID to enrich (omit for all unenriched)"}
                limit: {type: integer}
      responses:
        '200':
          description: Enrichment result

  # Spectre — Intelligence Pipeline Triggers
  /enaibleusovereignty/api/v1/spectre/intelligence/seed:
    post:
      summary: Trigger Spectre Intelligence seed job
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Job triggered

  /enaibleusovereignty/api/v1/spectre/intelligence/enrich:
    post:
      summary: Trigger Spectre Intelligence enrich job
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Job triggered

  /enaibleusovereignty/api/v1/spectre/intelligence/scout:
    post:
      summary: Trigger Spectre Intelligence scout research job
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Job triggered

  # Spectre — Hopper Suggest Topic
  /enaibleusovereignty/api/v1/spectre/hopper/suggest-topic:
    post:
      summary: Suggest a topic for a hopper domain based on keyword intelligence
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain: {type: string}
      responses:
        '200':
          description: Topic suggestion

  # Mail — Triage
  /enaibleusovereignty/api/v1/mail/triage:
    post:
      summary: AI-triage incoming emails
      security:
        - cookieAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                account_email: {type: string}
                limit:         {type: integer}
      responses:
        '200':
          description: Triage result

  # Auth — API Key Expiry
  /enaibleusovereignty/api/v1/api-keys/{id}/expiry:
    put:
      summary: Set or extend API key expiry
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [expires_at]
              properties:
                expires_at: {type: string, format: date-time, description: "New expiry timestamp (RFC3339)"}
      responses:
        '200':
          description: Expiry updated

  /enaibleusovereignty/api/v1/enrollment/status:
    get:
      summary: Get API key enrollment status for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Enrollment status

  # License — Token Verify
  /enaibleusovereignty/api/v1/license/token/verify:
    post:
      summary: Verify a license token
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token]
              properties:
                token: {type: string}
      responses:
        '200':
          description: Token verification result

  # Features — Update
  /enaibleusovereignty/api/v1/features/{id}:
    put:
      summary: Update feature configuration
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Feature updated

  # Profile — Additional
  /enaibleusovereignty/api/v1/profile/claim-ai-mail-account:
    post:
      summary: Claim an AI mail account for current user
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Account claimed

  /enaibleusovereignty/api/v1/profile/link-ai-mail-account:
    post:
      summary: Link an existing AI mail account to current user
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [account_id]
              properties:
                account_id: {type: string}
      responses:
        '200':
          description: Account linked

  /enaibleusovereignty/api/v1/profile/selected-ai-mail-account:
    patch:
      summary: Update the selected AI mail account
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [account_id]
              properties:
                account_id: {type: string}
      responses:
        '200':
          description: Selected account updated

  /enaibleusovereignty/api/v1/profile/vault-devices/{id}:
    delete:
      summary: Remove a specific trusted vault device
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Device removed

  # Blog — Item
  /enaibleusovereignty/api/v1/blog/{id}:
    get:
      summary: Get blog post by ID or slug
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Blog post
    put:
      summary: Update a blog post
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete a blog post
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  # ── Memory Phase 4 Surfaces (2026-05-12) ────────────────────────────────
  /enaibleusovereignty/api/v1/memory/graph:
    get:
      summary: Memory graph — entities + tags as nodes, mentions as edges
      description: |
        Returns a node/edge view of the active memory store for graph-style
        visualisation. Nodes carry a `kind` of entity | tag | concept
        (consolidation-synthesised summaries). Edges connect entities to
        their tags. Archived memories are excluded. Cap: 2000 memories.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Graph snapshot
          content:
            application/json:
              schema:
                type: object
                properties:
                  nodes:
                    type: array
                    items:
                      type: object
                      properties:
                        id:     {type: string}
                        label:  {type: string}
                        kind:   {type: string, enum: [entity, tag, concept]}
                        weight: {type: integer}
                  edges:
                    type: array
                    items:
                      type: object
                      properties:
                        source: {type: string}
                        target: {type: string}

  /enaibleusovereignty/api/v1/memory/conflicts:
    get:
      summary: List LLM-detected memory contradictions
      description: |
        Conflicts persisted by the periodic conflict-detection worker.
        Grouped by entity, carrying a one-sentence LLM-written summary
        plus a severity tier. Resolved conflicts are still returned with
        `resolved=true` so the UI can offer a "show resolved" toggle.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Conflict list
          content:
            application/json:
              schema:
                type: object
                properties:
                  conflicts:
                    type: array
                    items: {$ref: '#/components/schemas/MemoryConflict'}

  /enaibleusovereignty/api/v1/memory/conflicts/{id}/resolve:
    post:
      summary: Mark a memory conflict as resolved
      description: Flips `resolved=true` on the conflict record. Idempotent.
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Resolved
          content:
            application/json:
              schema:
                type: object
                properties:
                  resolved: {type: boolean}

  /enaibleusovereignty/api/v1/models/health:
    get:
      summary: Routing health — per-model rolling stats
      description: |
        Returns the live in-memory health snapshot (last 100 calls per
        provider+model) used by the Sentinel AI Tools Routing Health
        panel. Each entry includes total calls, success/failure counts,
        failure rate, p50/p95 latency, last error / success timestamps,
        and last error message. Sorted worst-first so brown-out models
        float to the top. Window resets on process restart.
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Health snapshot
          content:
            application/json:
              schema:
                type: object
                properties:
                  models:
                    type: array
                    items:
                      type: object
                      properties:
                        provider:         {type: string}
                        model:            {type: string}
                        total_calls:      {type: integer}
                        success_count:    {type: integer}
                        failure_count:    {type: integer}
                        failure_rate_pct: {type: integer}
                        latency_p50_ms:   {type: integer}
                        latency_p95_ms:   {type: integer}
                        last_call_at:     {type: string, format: date-time, nullable: true}
                        last_error_at:    {type: string, format: date-time, nullable: true}
                        last_error_msg:   {type: string, nullable: true}
                        last_success_at:  {type: string, format: date-time, nullable: true}

  # ── Competitive Analysis suite (RequirePro; continuous schedule is Enterprise) ──
  /enaibleusovereignty/api/v1/competitive/analyses:
    get:
      summary: List the current user's competitive analyses
      tags: [Competitive]
      security:
        - cookieAuth: []
      responses:
        '200':
          description: Analyses list
    post:
      summary: Create a competitive analysis and trigger its initial run
      tags: [Competitive]
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, our_software, competitor_domains]
              properties:
                name:                  {type: string}
                description:           {type: string}
                our_software:
                  type: array
                  items:
                    type: object
                    required: [name, url]
                    properties:
                      name:        {type: string}
                      url:         {type: string}
                      description: {type: string}
                      focus_areas: {type: array, items: {type: string}}
                competitor_domains:
                  type: array
                  items:
                    type: object
                    required: [url]
                    properties:
                      url:            {type: string}
                      label:          {type: string}
                      respect_robots: {type: boolean}
                      tos_override:   {type: boolean}
                      focus_areas:    {type: array, items: {type: string}}
                schedule_cron:         {type: string, description: "Enterprise-only; dropped for Pro"}
                respect_robots_global: {type: boolean}
                focus_areas:           {type: array, items: {type: string}}
      responses:
        '201':
          description: Analysis created; initial run dispatched

  /enaibleusovereignty/api/v1/competitive/analyses/{id}:
    get:
      summary: Get one competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Analysis record
        '404':
          description: Not found or not owned
    patch:
      summary: Update a competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Updated analysis
    delete:
      summary: Delete a competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Deleted

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/run:
    post:
      summary: Trigger a run of a competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '202':
          description: Run dispatched

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/pause:
    post:
      summary: Pause a competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Paused

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/resume:
    post:
      summary: Resume a paused competitive analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Resumed

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/competitors:
    get:
      summary: List the competitor profiles for an analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Competitor profiles

  /enaibleusovereignty/api/v1/competitive/competitors/{cid}:
    get:
      summary: Get one competitor profile
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: cid, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Competitor profile

  /enaibleusovereignty/api/v1/competitive/competitors/{cid}/snapshots:
    get:
      summary: List captured snapshots for a competitor
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: cid, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Snapshots list

  /enaibleusovereignty/api/v1/competitive/competitors/{cid}/diff:
    get:
      summary: Get the latest snapshot diff for a competitor
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: cid, in: path, required: true, schema: {type: string}}
        - {name: from, in: query, schema: {type: string}, description: "Snapshot id (defaults to penultimate)"}
        - {name: to,   in: query, schema: {type: string}, description: "Snapshot id (defaults to latest)"}
      responses:
        '200':
          description: Diff payload

  /enaibleusovereignty/api/v1/competitive/competitors/{cid}/refresh:
    post:
      summary: Re-crawl and re-synthesise a single competitor
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: cid, in: path, required: true, schema: {type: string}}
      responses:
        '202':
          description: Refresh dispatched

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/reports:
    get:
      summary: List reports generated for an analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id,   in: path, required: true, schema: {type: string}}
        - {name: type, in: query, schema: {type: string}, description: "Filter by report_type"}
      responses:
        '200':
          description: Reports list

  /enaibleusovereignty/api/v1/competitive/reports/{id}:
    get:
      summary: Get one competitive report
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Report record

  /enaibleusovereignty/api/v1/competitive/reports/{id}/export:
    get:
      summary: Export a competitive report (md, json, pdf, docx)
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id,     in: path, required: true, schema: {type: string}}
        - {name: format, in: query, schema: {type: string, enum: [md, json, pdf, docx], default: md}}
      responses:
        '200':
          description: Exported report (file or JSON)
        '503':
          description: Export format not yet generated

  /enaibleusovereignty/api/v1/competitive/analyses/{id}/battlecards:
    get:
      summary: List battlecards for an analysis
      tags: [Competitive]
      security:
        - cookieAuth: []
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        '200':
          description: Battlecards list

  # Internal — Live Status (not public)
  /internal/nexus/live-status:
    get:
      summary: Internal live status for audit agent (no auth)
      description: Internal-only endpoint used by the Nexus Audit agent to poll live agent status. Not exposed externally.
      responses:
        '200':
          description: Live agent status

components:
  schemas:
    # ── Memory phase 2/3/4 schemas (2026-05-12) ────────────────────────────
    # The phase rollout added these fields incrementally:
    #   tags / canonical_form  (phase 1 enrichment)
    #   is_concept / child_ids (phase 2 consolidation worker)
    #   archived / pinned      (phase 2 decay sweep)
    # Documented here so consumers can serialise the full Memory shape.
    Memory:
      type: object
      properties:
        id:               {type: string}
        user_id:          {type: string, nullable: true, description: 'nil = global memory'}
        type:             {type: string, description: 'preference | event | learned'}
        category:         {type: string}
        content:          {type: string, description: 'canonical (LLM-normalised) form after enrichment'}
        entity:           {type: string}
        entity_type:      {type: string, description: 'person | animal | pet | place | organization | object | concept'}
        relationship:     {type: string, description: 'pet | friend | best_friend | family | colleague | hobby | favorite | team | other'}
        keywords:
          type: array
          items:
            type: object
            properties:
              term:     {type: string}
              score:    {type: number}
              source:   {type: string}
              category: {type: string}
        tags:
          type: array
          items: {type: string}
          description: 'Coarse topical labels (food / pets / work / health …). 2-5 per memory. Substrate for the Memory Graph + consolidation worker.'
        canonical_form:
          type: string
          description: 'LLM-normalised one-sentence factual summary. Mirror of content after enrichment. Reused as the dedup hash basis.'
        content_hash:     {type: string}
        importance:       {type: number, description: '0.0 – 1.0'}
        sentiment:        {type: number, description: '-1.0 – 1.0'}
        source:           {type: string, description: 'explicit | auto | enrichment | consolidation'}
        enriched:         {type: boolean}
        is_concept:
          type: boolean
          description: 'true when this memory is a system-synthesised concept from the consolidation worker. Concepts are excluded from being themselves consolidated.'
        child_ids:
          type: array
          items: {type: string}
          description: 'For concept memories: source memory IDs the concept summarises.'
        archived:
          type: boolean
          description: 'Set true by the decay sweep when last_accessed_at older than MEMORY_DECAY_DAYS (default 90). Archived memories are excluded from Search() but retrievable by direct ID.'
        pinned:
          type: boolean
          description: 'Set true by the decay sweep when access_count >= 5. Pinned memories are exempt from archival.'
        web_facts:
          type: array
          items:
            type: object
            properties:
              claim:      {type: string}
              source_url: {type: string}
              fetched_at: {type: string}
        web_enriched_at:  {type: string, format: date-time, nullable: true}
        created_at:       {type: string, format: date-time}
        updated_at:       {type: string, format: date-time}
        last_accessed_at: {type: string, format: date-time}
        access_count:     {type: integer}

    MemoryConflict:
      type: object
      properties:
        id:          {type: string}
        user_id:     {type: string, nullable: true}
        entity:      {type: string}
        memory_ids:  {type: array, items: {type: string}}
        summary:     {type: string, description: 'One-sentence LLM-written explanation of the contradiction'}
        severity:    {type: string, enum: [low, high]}
        resolved:    {type: boolean}
        detected_at: {type: string, format: date-time}

    # Spectre watch additions (2026-05-11 sub-page promotion + 2026-05-12 write-fail badge)
    WatchEntryExtensions:
      type: object
      description: 'Fields added to WatchEntry in 2026-05 — read alongside the existing watch schema.'
      properties:
        parent_watch_id:
          type: string
          nullable: true
          description: 'Set on watches auto-promoted from a parent multi-page crawl. UI groups children under parent while keeping each independent (own interval / status / Discord toggle).'
        last_write_error:
          type: string
          nullable: true
          description: 'Last PocketBase persistence failure (e.g. validation_max_text_constraint). Cleared on next successful write. Surfaced as a red badge in the UI.'
        last_write_error_at: {type: string, format: date-time, nullable: true}

    MealEntry:
      type: object
      properties:
        id:          {type: string}
        week_date:   {type: string, description: "YYYY-MM-DD Monday of the week"}
        day_of_week: {type: integer, minimum: 0, maximum: 6, description: "0=Mon … 6=Sun"}
        plan_type:   {type: string, enum: [eaten, planned]}
        breakfast:   {type: string}
        lunch:       {type: string}
        dinner:      {type: string}
        snack:       {type: string}
        notes:       {type: string}
        person:      {type: string, enum: [owner, partner, children, family]}
        user_id:     {type: string}
        created:     {type: string, format: date-time}
        updated:     {type: string, format: date-time}

    ScheduleItem:
      type: object
      required: [title]
      properties:
        id:            {type: string}
        title:         {type: string}
        description:   {type: string}
        frequency:     {type: string, enum: [daily, weekly, monthly, once]}
        day_of_week:   {type: integer, minimum: 0, maximum: 6, description: "Sun=0; used when frequency=weekly"}
        day_of_month:  {type: integer, minimum: 1, maximum: 31, description: "used when frequency=monthly"}
        specific_date: {type: string, description: "YYYY-MM-DD; required when frequency=once"}
        start_time:    {type: string, description: "HH:MM 24h"}
        end_time:      {type: string, description: "HH:MM 24h"}
        priority:      {type: string, enum: [low, medium, high, critical]}
        color:         {type: string}
        is_active:     {type: boolean}
        sort_order:    {type: integer}
        tags:          {type: array, items: {type: string}, description: "Family tags: adelita, vivian, asher, alyssia, seleena"}
        location:      {type: string, description: "Free-form address or a full Maps URL"}
        notify:        {type: boolean, description: "Post a Discord reminder ~15 min before this fires"}
        user_id:       {type: string}
        created:       {type: string, format: date-time}
        updated:       {type: string, format: date-time}

    Deal:
      type: object
      properties:
        id:               {type: string}
        title:            {type: string}
        source_type:      {type: string, enum: [text, pdf, docx]}
        filename:         {type: string}
        status:           {type: string, enum: [analyzing, complete, failed]}
        overall_score:    {type: number, format: float, description: "0–10 composite MEDDPICC score"}
        recommendation:   {type: string}
        scores:
          type: object
          properties:
            metrics:            {type: number, format: float}
            economic_buyer:     {type: number, format: float}
            decision_criteria:  {type: number, format: float}
            decision_process:   {type: number, format: float}
            paper_process:      {type: number, format: float}
            identify_pain:      {type: number, format: float}
            champion:           {type: number, format: float}
            competition:        {type: number, format: float}
        feedback:
          type: object
          description: Per-category feedback (decrypted). Keys are MEDDPICC categories.
          additionalProperties:
            type: object
            properties:
              summary:  {type: string}
              present:  {type: array, items: {type: string}}
              missing:  {type: array, items: {type: string}}
              actions:  {type: array, items: {type: string}}
        questions:   {type: array, items: {type: string}}
        strengths:   {type: array, items: {type: string}}
        gaps:        {type: array, items: {type: string}}
    MessengerChannel:
      type: object
      properties:
        id:         {type: string}
        name:       {type: string}
        type:       {type: string, enum: [dm, channel]}
        members:    {type: array, items: {type: string}}
        created_by: {type: string}
        created:    {type: string, format: date-time}
    MessengerMessage:
      type: object
      properties:
        id:         {type: string}
        channel_id: {type: string}
        sender_id:  {type: string}
        body:       {type: string, description: Plaintext body (decrypted on the server)}
        mentions:   {type: array, items: {type: string}}
        created:    {type: string, format: date-time}
    MessengerUser:
      type: object
      properties:
        id:    {type: string}
        email: {type: string}
        name:  {type: string}
    ToolResult:
      type: object
      properties:
        status:
          type: string
          enum: [idle, ok, warning, critical, error]
        last_run:
          type: string
          format: date-time
        summary:
          type: string
        findings:
          type: integer
        details:
          type: array
          items:
            type: string
        report_id:
          type: string

    Todo:
      type: object
      properties:
        id: {type: string}
        title: {type: string}
        description: {type: string}
        status:
          type: string
          enum: [intake, in_progress, done_evaluation, archived]
        priority:
          type: string
          enum: [low, medium, high, critical]
        category: {type: string}
        tags:
          type: array
          items: {type: string}
        keywords:
          type: array
          items: {type: string}
        parent_id: {type: string}
        sort_order: {type: integer}
        due_date: {type: string}
        user_id: {type: string}
        created: {type: string}
        updated: {type: string}
    CreateTodoRequest:
      type: object
      required: [title, user_id]
      properties:
        title: {type: string}
        description: {type: string}
        status:
          type: string
          enum: [intake, in_progress, done_evaluation, archived]
          default: intake
        priority:
          type: string
          enum: [low, medium, high, critical]
          default: medium
        category: {type: string}
        tags:
          type: array
          items: {type: string}
        keywords:
          type: array
          items: {type: string}
        parent_id: {type: string}
        sort_order: {type: integer}
        due_date: {type: string}
        user_id: {type: string}
    UpdateTodoRequest:
      type: object
      properties:
        title: {type: string}
        description: {type: string}
        status:
          type: string
          enum: [intake, in_progress, done_evaluation, archived]
        priority:
          type: string
          enum: [low, medium, high, critical]
        category: {type: string}
        tags:
          type: array
          items: {type: string}
        keywords:
          type: array
          items: {type: string}
        parent_id: {type: string}
        sort_order: {type: integer}
        due_date: {type: string}

    ConnectorConfig:
      type: object
      description: Service-specific connection parameters. Only fields relevant to the chosen service need to be provided.
      properties:
        # Microsoft (SharePoint + Office 365)
        tenant_id:      {type: string, description: Azure AD Directory (tenant) ID}
        client_id:      {type: string, description: App Registration Application (client) ID}
        client_secret:  {type: string, description: App Registration client secret}
        site_url:       {type: string, description: Target SharePoint site URL (SharePoint only)}
        user_email:     {type: string, description: Primary mailbox address (Office 365 only)}
        # Salesforce
        instance_url:     {type: string, description: Salesforce instance URL e.g. https://yourorg.salesforce.com}
        sf_client_id:     {type: string, description: Connected App Consumer Key}
        sf_client_secret: {type: string, description: Connected App Consumer Secret}
        username:         {type: string, description: Salesforce login username}
        password:         {type: string, description: Salesforce password}
        security_token:   {type: string, description: Salesforce user security token (appended to password)}
        api_version:      {type: string, description: Salesforce API version e.g. v59.0}
        # Slack
        bot_token:        {type: string, description: Bot User OAuth Token (xoxb-...)}
        app_token:        {type: string, description: App-Level Token for Socket Mode (xapp-..., optional)}
        signing_secret:   {type: string, description: App signing secret for payload verification}
        default_channel:  {type: string, description: Default channel ID or name for outgoing messages}

    Connector:
      type: object
      properties:
        id:             {type: string}
        user_id:        {type: string}
        service:
          type: string
          enum: [sharepoint, office365, salesforce, slack]
        name:           {type: string}
        enabled:        {type: boolean}
        config:
          $ref: '#/components/schemas/ConnectorConfig'
        status:
          type: string
          enum: [untested, connected, error]
        last_tested_at: {type: string, format: date-time}
        error_message:  {type: string}
        created:        {type: string, format: date-time}
        updated:        {type: string, format: date-time}

    ConnectorRequest:
      type: object
      required: [service, name]
      properties:
        service:
          type: string
          enum: [sharepoint, office365, salesforce, slack]
        name:    {type: string}
        enabled: {type: boolean, default: true}
        config:
          $ref: '#/components/schemas/ConnectorConfig'

    TranslateRequest:
      type: object
      required: [source_lang, target_lang, content]
      properties:
        source_lang:
          type: string
          enum: [ENG, DUTCH, FRENCH, GERMAN, SPANISH]
          description: Source language code
        target_lang:
          type: string
          enum: [ENG, DUTCH, FRENCH, GERMAN, SPANISH]
          description: Target language code (must differ from source_lang)
        content:
          type: string
          description: Text to translate (plain text, Markdown, or JSON)
        format:
          type: string
          enum: [txt, md, json]
          default: txt
          description: >
            Content format. When omitted, format is auto-detected:
            JSON object/array → json, Markdown markers (##, **) → md, otherwise → txt.
        download:
          type: boolean
          default: false
          description: When true, the response is a binary file download instead of JSON

    TranslateResult:
      type: object
      properties:
        translated:
          type: string
          description: Translated content in the requested format
        format:
          type: string
          enum: [txt, md, json]
          description: Detected/confirmed content format
        word_count:
          type: integer
          description: Approximate word count of the translated output
        duration_ms:
          type: integer
          description: LLM round-trip duration in milliseconds

  securitySchemes:
    cookieAuth:
      type: apiKey
      in: cookie
      name: pb_auth
    BearerAuth:
      type: http
      scheme: bearer
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

security:
  - cookieAuth: []
