Skip to main content
The server SDK is configured in code through the Firstflow constructor plus a couple of environment values. There is no FirstFlow service, so there are no service URLs or API keys to point at.

Constructing Firstflow

persistence
FirstflowLLMPersistence
required
Where rows are written. Pass createSupabaseLLMPersistence(supabase) from @firstflow/runtime-server/supabase, or implement the interface for another store.
captureContent
boolean
default:"false"
Store prompt and completion text in firstflow_conversation_messages. Off by default only metadata (tokens, cost, latency, status) is recorded. Enable it deliberately and match your RLS and retention to your privacy posture.
defaultMetadata
Record<string, unknown>
Tags merged into every recorded call’s metadata. Per-call firstflow.metadata is merged on top.

Environment

The SDK itself needs only your Supabase project URL and service-role key (for the adapter):
SUPABASE_SERVICE_ROLE_KEY bypasses Row Level Security. Keep it server-only, never expose it to the browser, and never commit it.
No AI key is read by FirstFlow. The key belongs to the LLM client you build and hand to ff.wrap(...) / createAIClient(...). Provide it however you like the provider SDK’s default variable (ANTHROPIC_API_KEY, OPENAI_API_KEY), your own env name passed explicitly, or createAIClient({ baseURL, apiKey }) for an OpenAI-compatible endpoint. See the provider tabs in self-hosting Configuration and Wrap your LLM client.

Custom persistence

Target a non-Supabase store by implementing FirstflowLLMPersistence:
Only recordCall is required; optional methods unlock messages, traces, signals, and the classifier’s read path.

Signed identity tokens

When you proxy SDK writes through your own API, signUserToken mints a tamper-proof identity payload your backend can verify:
Standard HS256 JWTs any JWT library can verify them.

Next

Start with wrapping your client, or see what gets recorded.