openapi: 3.1.0
info:
  title: Kioku API
  version: 0.1.0
  description: |
    The general memory layer for agents — cross-project, cross-device.
    Markdown is the single source of truth; every write is a proposal;
    the server runs zero LLMs — compilation and audit are done by connected
    agents via the task queue (see the /mcp tool contract).
    Auth: Authorization: Bearer kioku_… (one credential per device / agent).
servers:
  - url: /v1
security:
  - bearer: []
components:
  securitySchemes:
    bearer: { type: http, scheme: bearer }
  schemas:
    Page:
      type: object
      required: [id, type, title, body]
      properties:
        id: { type: string, description: lowercase-hyphen slug }
        type: { type: string, description: note/reference/entity/how-to/memory… }
        title: { type: string }
        abstract: { type: string, description: one-sentence recall summary }
        keywords: { type: array, items: { type: string }, description: English terms + native aliases }
        tags: { type: array, items: { type: string } }
        raws: { type: array, items: { type: string }, description: provenance raw slugs }
        body: { type: string, description: Markdown body }
        pinned: { type: boolean }
        op: { type: string, enum: [upsert, delete] }
paths:
  /auth/config:
    get: { summary: Auth configuration (GitHub client_id, dev mode), security: [] }
  /auth/github/exchange:
    post: { summary: Exchange a GitHub access token for a kioku token (Device Flow exit), security: [] }
  /me:
    get: { summary: Current user }
  /tokens:
    get: { summary: List my credentials }
    post: { summary: Generate a manual PAT (CI / scripts fallback) }
  /tokens/{id}/revoke:
    post: { summary: Revoke a credential }
  /spaces:
    get: { summary: My spaces }
    post: { summary: Create a team space }
  /spaces/{slug}:
    get: { summary: Space info and stats }
  /spaces/{slug}/members:
    get: { summary: List members }
    post: { summary: Invite a member (owner) }
  /spaces/{slug}/pages:
    get: { summary: Page catalog (L1 index) }
  /spaces/{slug}/pages/{id}:
    get: { summary: Read a page (frontmatter + body) }
  /spaces/{slug}/pages/{id}/pin:
    post: { summary: Pin into the brief (editor+) }
  /spaces/{slug}/pages/{id}/publish:
    post: { summary: Publish as a public page (owner) → /p/{slug}/llms.txt }
  /spaces/{slug}/search:
    get: { summary: L2 search (BM25 + lexical fallback; q/limit/type/tag/budget) }
  /spaces/{slug}/changes:
    get: { summary: Incremental sync (cursor → revisions + next cursor) }
  /spaces/{slug}/brief:
    get: { summary: L0 session context packet (≤2000 tokens) }
  /spaces/{slug}/proposals:
    get: { summary: List proposals (?status=pending) }
    post: { summary: Submit a proposal (every write is a proposal; auto-merged in personal spaces) }
  /spaces/{slug}/proposals/{id}/{action}:
    post: { summary: approve / reject (editor+) }
  /spaces/{slug}/raws:
    get: { summary: List raw sources (with compile status) }
    post: { summary: Store a raw source (enters the compile queue) }
  /spaces/{slug}/raws/{raw}/content:
    get: { summary: Read a raw source's original text }
  /spaces/{slug}/tasks:
    get: { summary: Agent task queue (raws to compile + pages to audit) }
  /spaces/{slug}/audit/{pageId}/done:
    post: { summary: Report an audit result (fixedPages enter the review inbox) }
  /spaces/{slug}/audit:
    get: { summary: Audit log (user + agent dual attribution) }
