Skip to main content

kickoff-intake

kickoff-intake is deliberately unusual among SABLE's Edge Functions: it is the only public, unauthenticated surface in the entire system. A stakeholder opens an invite link (interview.html#t=<token>) with no SABLE login at all, and works through a short, adaptive AI interview (or fills a form instead).

Auth model: a token, not a JWT

Because there is no logged-in user, config.toml sets verify_jwt = false for this function — authentication is a high-entropy invite token, checked by hash lookup, not a Supabase session. This is a deliberate, narrow exception to the JWT-everywhere pattern the rest of the app follows, scoped as tightly as the function's own write/read boundaries below make it.

What it can read and write — and nothing more

  • Write-only to its own interview's rows. The function cannot touch any other interview, project, or spine data.
  • Returns no spine data beyond the project's display name and the stakeholder's own name — nothing about the account, other stakeholders, or SABLE's broader state leaks through this surface.
  • On completion, it writes one sources row (type = 'manual', external_id = 'kickoff:<id>') — the provenance root interview-synthesize later reads.

Hardening, because this is the one function anyone on the internet can reach

  • Token hash lookup (never a plaintext token comparison).
  • Expiry and revoke checks on every request.
  • A per-interview rate limit (20 turns/minute).
  • Body-size caps: 6,000 characters for a single answer, 60,000 for the full rendered transcript stored as the source.
  • An audit trail on every event.

The interview itself

The canonical themes an interview must cover — success criteria, pain points, risks/concerns, data/access, and scope/priorities — are built in, so the conversational interviewer works with zero seeding even for a brand-new project. A project or org can override/extend these via interview_questions, but nothing has to be configured for a first interview to run.

Where the code lives

  • sable-agents-demo/supabase/functions/kickoff-intake/index.ts
  • sable-agents-demo/supabase/functions/config.toml — the verify_jwt = false exception for this function
  • sable-agents-demo/web/interview.html
  • sable-agents-demo/web/api/kickoff.js, _kickoff.js — the invite-link creation side