collabGPT

OAuth Action backend for a private or invite‑only Custom GPT to capture and share notes with attribution. Built with Bun + Hono + Zod + zod‑openapi, Clerk OAuth (OIDC), and a single JSON file on a persistent volume.

⚠️ Important Zod Pattern Note

NEVER use z.record(z.any()) - this is invalid Zod syntax and will cause runtime errors.

ALWAYS use z.record(z.any(), z.any()) - Zod’s record type requires two arguments:

Example:

// ❌ WRONG - Will cause errors
z.record(z.any())

// ✅ CORRECT
z.record(z.any(), z.any())  // any key, any value
z.record(z.string(), z.number())  // string keys, number values

What It Does

Quick Start (Dev)

  1. Run the orchestrator from repo root:
    • bun run start
    • This picks up collabGPT/server.agent.md and starts the API on http://localhost:8080.
  2. Dev auth (no Clerk needed):
    • Default user is sub=dev_sub, email=dev@example.com.
    • Override via headers: Authorization: Bearer dev:my_sub:me@example.com.
    • Or set env: CLERK_DEV_ALLOW_INSECURE=1, DEV_SUB, DEV_EMAIL.

Production Auth (Clerk OIDC)

Userscripts System

The API now includes a complete userscripts management system for browser automation and enhancement.

Architecture

Dual Router Pattern: We use separate routers for public API endpoints vs internal serving routes:

  1. Public API Routes (api/routes/userscripts.ts):
    • Mounted at /userscripts
    • Protected by auth middleware
    • Returns JSON responses
    • Used for management operations (list, compile, update)
    • Documented in OpenAPI spec
  2. Internal Serving Routes (api/internal/userscripts.ts):
    • Also mounted at /userscripts (overlapping paths)
    • Serves HTML pages and raw JavaScript
    • Sets authentication cookies
    • Used for browser installation flow
    • Not included in OpenAPI (intentionally)

Userscript Workflow

  1. Development: Write userscripts in scripts/userscripts/*.js
  2. Compilation: POST to /userscripts/:id/compile adds metadata headers
  3. Installation: Visit /userscripts/:id/install in browser
    • Sets authentication cookie (collabgpt_auth)
    • Shows installation page with button
  4. Auto-Update: Scripts check /userscripts/:id/meta for new versions
  5. Download: Browser fetches from /userscripts/:id/script

Example Userscripts

Userscripts use cookie-based auth since they can’t easily manage Bearer tokens:

Endpoints & Schemas

Knowledge Base Endpoints

Sourcegraph Endpoints

Userscripts Endpoints (Public API)

Userscripts Endpoints (Internal Serving)

System Endpoints

Storage

Run Manually (without orchestrator)

bun run collabGPT/server.ts
# PORT=8080 by default

Static Site (Astro)

OpenAPI Snippet (for GPT Action)

paths:
  /notes:
    get:
      operationId: listNotes
      summary: List shared notes
      responses:
        "200": { description: OK }
    post:
      operationId: createNote
      summary: Create a new note attributed to the caller
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text]
              properties:
                text: { type: string }
      responses:
        "200": { description: Created }
  /notes/search:
    get:
      operationId: searchNotes
      parameters:
        - in: query
          name: q
          required: true
          schema: { type: string }
      responses:
        "200": { description: OK }

Deployment (Fly.io)

Dockerfile (example):

FROM oven/bun:1.1
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
EXPOSE 8080
ENV PORT=8080
CMD ["bun", "run", "collabGPT/server.ts"]

fly.toml (sketch):

app = "collabgpt-notes"
primary_region = "den"

[build]
  dockerfile = "Dockerfile"

[[mounts]]
  source = "kb_data"
  destination = "/data"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true

Volume:

fly volumes create kb_data --region den --size 1

Env to set in Fly:

Voice UX Caveat

Advanced Voice Mode in ChatGPT currently doesn’t trigger external Actions. Include a brief instruction in your GPT for voice users to switch to text when they want to save/read notes.