⚙️ Configuration
Curiositi is configured through environment variables. A single .env.example file at the repository root contains all available configuration options shared across apps.
Quick Setup
Section titled “Quick Setup”Copy the example environment file from the repository root:
cp .env.example .envThis single .env file at the root is used by all apps via Turborepo.
Environment Variables
Section titled “Environment Variables”The following environment variables are used by Curiositi. All variables listed below are defined in the root .env.example file.
Shared (Platform & Worker)
Section titled “Shared (Platform & Worker)”These variables are required by both the platform and worker apps:
Note:
POSTGRES_URLis directly used by the@curiositi/dbpackage. The platform accesses the database through this shared package, so the variable is not explicitly validated in the platform’s env.ts.
| Variable | Required | Description |
|---|---|---|
POSTGRES_URL | Yes | PostgreSQL connection string |
S3_ENDPOINT | Yes | S3-compatible storage endpoint URL |
S3_BUCKET | Yes | S3 bucket name |
S3_ACCESS_KEY_ID | Yes | S3 access key |
S3_SECRET_ACCESS_KEY | Yes | S3 secret key |
OPENAI_API_KEY | Yes | OpenAI API key (required for file processing/embeddings in worker) |
Connection string format:
postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]Platform Only
Section titled “Platform Only”| Variable | Required | Description |
|---|---|---|
PLATFORM_URL | Yes | Public URL of the platform app (default: http://localhost:3030) |
WORKER_URL | Conditional | URL of the worker service (required if QUEUE_PROVIDER=qstash, default: http://localhost:3040) |
BETTER_AUTH_SECRET | Yes | Secret key for Better Auth session signing |
BETTER_AUTH_GOOGLE_CLIENT_ID | Yes | Google OAuth client ID |
BETTER_AUTH_GOOGLE_CLIENT_SECRET | Yes | Google OAuth client secret |
QUEUE_PROVIDER | No | Queue provider: "qstash" (default, cloud) or "local" (self-hosted bunqueue) |
QSTASH_TOKEN | Conditional | Upstash QStash token (required if QUEUE_PROVIDER=qstash) |
QSTASH_URL | No | Custom QStash URL (uses default Upstash endpoint if not set) |
BUNQUEUE_HOST | Conditional | bunqueue server host (required if QUEUE_PROVIDER=local, default: localhost) |
BUNQUEUE_PORT | Conditional | bunqueue server port (required if QUEUE_PROVIDER=local, default: 6789) |
RESEND_API_KEY | No | Resend API key for email features |
EMAIL_FROM_ADDRESS | Conditional | Sender email address (required if RESEND_API_KEY is set, default: noreply@curiositi.com) |
Client-Side (Platform)
Section titled “Client-Side (Platform)”| Variable | Required | Description |
|---|---|---|
VITE_APP_TITLE | No | Application title displayed in the browser |
VITE_SENTRY_DSN | No | Sentry DSN for error tracking |
VITE_SENTRY_ORG | No | Sentry organization slug |
VITE_SENTRY_PROJECT | No | Sentry project slug |
Worker Only
Section titled “Worker Only”| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY | Yes | OpenAI API key (required for embeddings and document extraction) |
WORKER_SENTRY_DSN | No | Sentry DSN for worker error tracking |
SENTRY_ENVIRONMENT | No | Sentry environment label (default: development) |
QSTASH_CURRENT_SIGNING_KEY | Conditional | QStash current signing key (required if QUEUE_PROVIDER=qstash) |
QSTASH_NEXT_SIGNING_KEY | Conditional | QStash next signing key (required if QUEUE_PROVIDER=qstash) |
AI Providers & Search (Platform & Worker)
Section titled “AI Providers & Search (Platform & Worker)”At least one AI provider is strongly recommended to enable Agentic Chat and embeddings. Web Search requires Firecrawl.
| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY | Conditional | OpenAI API Key (required for OpenAI Chat and Embeddings) |
ANTHROPIC_API_KEY | Conditional | Anthropic API Key (required for Anthropic Claude Chat) |
GOOGLE_GENERATIVE_AI_API_KEY | Conditional | Google API Key (required for Gemini Chat and Embeddings) |
OLLAMA_BASE_URL | Conditional | Base URL for Ollama local instances |
FIRECRAWL_API_KEY | Conditional | API Key for the Firecrawl web fetcher tool |
Monitoring
Section titled “Monitoring”| Variable | Required | Description |
|---|---|---|
SENTRY_AUTH_TOKEN | No | Sentry auth token for source map uploads |
Full .env.example
Section titled “Full .env.example”# === SHARED (Platform & Worker) ===
# Database - Connection string for the PostgreSQL databasePOSTGRES_URL=""
# File Storage - S3 compatible storage settings for AWS, GCP, or Cloudflare R2S3_ENDPOINT=""S3_BUCKET=""S3_ACCESS_KEY_ID=""S3_SECRET_ACCESS_KEY=""
# Worker AI provider credential (required for file processing / embeddings)OPENAI_API_KEY=""
# Worker monitoringWORKER_SENTRY_DSN=""SENTRY_ENVIRONMENT="development"
# === PLATFORM ONLY ===
# Server Configuration - Basic application settings and environment URLsPLATFORM_URL="http://localhost:3030"WORKER_URL="http://localhost:3040"
# Authentication - Better Auth configuration and Google OAuth credentialsBETTER_AUTH_SECRET=""BETTER_AUTH_GOOGLE_CLIENT_ID=""BETTER_AUTH_GOOGLE_CLIENT_SECRET=""
# Queue Configuration# QUEUE_PROVIDER: "qstash" (default, cloud) or "local" (self-hosted bunqueue)QUEUE_PROVIDER="qstash"
# QStash (required if QUEUE_PROVIDER=qstash)QSTASH_TOKEN=""QSTASH_URL=""QSTASH_CURRENT_SIGNING_KEY=""QSTASH_NEXT_SIGNING_KEY=""
# bunqueue (required if QUEUE_PROVIDER=local)BUNQUEUE_HOST="localhost"BUNQUEUE_PORT="6789"
# Email (optional - enables email features when set)RESEND_API_KEY=""EMAIL_FROM_ADDRESS="noreply@curiositi.com"
# AI Providers - at least one is required for agent chatANTHROPIC_API_KEY=""GOOGLE_GENERATIVE_AI_API_KEY=""OLLAMA_BASE_URL=""
# Web Search (required if web search tool is enabled)FIRECRAWL_API_KEY=""
# Monitoring & Error Tracking - Sentry configuration for both client and serverVITE_SENTRY_DSN=""VITE_SENTRY_ORG=""VITE_SENTRY_PROJECT=""SENTRY_AUTH_TOKEN=""Configuration Validation
Section titled “Configuration Validation”Both the platform and worker validate environment variables at startup using @t3-oss/env-core with Zod schemas. Missing required variables will cause the application to fail fast with a clear error message.
Platform validation (apps/platform/src/env.ts):
import { createEnv } from "@t3-oss/env-core";import { z } from "zod";
export const env = createEnv({ server: { PLATFORM_URL: z.url(), QUEUE_PROVIDER: z.enum(["qstash", "local"]).default("qstash"), QSTASH_TOKEN: z.string().optional(), WORKER_URL: z.string().optional(), BUNQUEUE_HOST: z.string().default("localhost"), BUNQUEUE_PORT: z.coerce.number().default(6789), BETTER_AUTH_GOOGLE_CLIENT_ID: z.string(), BETTER_AUTH_GOOGLE_CLIENT_SECRET: z.string(), BETTER_AUTH_SECRET: z.string(), RESEND_API_KEY: z.string().optional(), EMAIL_FROM_ADDRESS: z.string().optional(), S3_ACCESS_KEY_ID: z.string(), S3_SECRET_ACCESS_KEY: z.string(), S3_BUCKET: z.string(), S3_ENDPOINT: z.string(), }, client: { VITE_APP_TITLE: z.string().min(1).optional(), VITE_SENTRY_DSN: z.string().optional(), VITE_SENTRY_ORG: z.string().optional(), VITE_SENTRY_PROJECT: z.string().optional(), }, // Conditional validation happens at runtime after env is loaded});
// Conditional validation:if (env.QUEUE_PROVIDER === "qstash") { if (!env.QSTASH_TOKEN || !env.WORKER_URL) { throw new Error("QSTASH_TOKEN and WORKER_URL are required when QUEUE_PROVIDER=qstash"); }}
if (env.RESEND_API_KEY && !env.EMAIL_FROM_ADDRESS) { throw new Error("EMAIL_FROM_ADDRESS is required when RESEND_API_KEY is set");}The platform performs conditional validation based on QUEUE_PROVIDER:
- If
qstash: requiresQSTASH_TOKENandWORKER_URL - If
local: requiresBUNQUEUE_HOSTandBUNQUEUE_PORT(defaults available)
Worker validation (apps/worker/src/env.ts):
import { createEnv } from "@t3-oss/env-core";import { z } from "zod";
export const env = createEnv({ server: { OPENAI_API_KEY: z.string(), S3_ACCESS_KEY_ID: z.string(), S3_SECRET_ACCESS_KEY: z.string(), S3_BUCKET: z.string(), S3_ENDPOINT: z.string(), POSTGRES_URL: z.url(), WORKER_SENTRY_DSN: z.string().optional(), SENTRY_ENVIRONMENT: z.string().optional(), QUEUE_PROVIDER: z.enum(["qstash", "local"]).default("qstash"), QSTASH_CURRENT_SIGNING_KEY: z.string().optional(), QSTASH_NEXT_SIGNING_KEY: z.string().optional(), BUNQUEUE_HOST: z.string().default("localhost"), BUNQUEUE_PORT: z.coerce.number().default(6789), }, // ...});
// Conditional validation:if (env.QUEUE_PROVIDER === "qstash" && (!env.QSTASH_CURRENT_SIGNING_KEY || !env.QSTASH_NEXT_SIGNING_KEY)) { throw new Error( "QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY are required when QUEUE_PROVIDER=qstash" );}Hardcoded Configuration
Section titled “Hardcoded Configuration”Some configuration values are set directly in code rather than through environment variables:
File Processing
Section titled “File Processing”| Setting | Value | Location |
|---|---|---|
| Max file size | 50MB | packages/share/src/constants/index.ts |
| Large image threshold | 5MB | packages/share/src/constants/index.ts |
| Chunk size | 300 tokens | apps/worker/src/lib/chunk.ts |
| Chunk overlap | 60 tokens | apps/worker/src/lib/chunk.ts |
| Embedding dimensions | 1536 | packages/db/src/schema.ts |
AI Models
Section titled “AI Models”AI model names are configured in packages/share/src/models/index.ts and packages/agent/src/constants.ts:
Default Chat Models (for Agentic Chat):
| Provider | Default Model |
|---|---|
| OpenAI | gpt-5-mini |
gemini-3-flash-preview | |
| Anthropic | claude-haiku-4-5 |
| Ollama | (user-configured) |
Embedding Models (for file processing):
| Provider | Embedding Model | Dimensions |
|---|---|---|
| OpenAI | text-embedding-3-small | 1536 |
gemini-embedding-001 | 1536 |
Text Extraction Models (for document/image processing in worker):
| Provider | Model |
|---|---|
| OpenAI | gpt-4o-mini |
gemini-2.0-flash |
| App | Port | Configuration |
|---|---|---|
| Platform | 3030 | apps/platform/package.json dev script |
| Worker | 3040 | apps/worker/src/index.ts |
Setting Up Services
Section titled “Setting Up Services”PostgreSQL with pgvector
Section titled “PostgreSQL with pgvector”Docker:
docker run -d \ --name curiositi-db \ -e POSTGRES_PASSWORD=postgres \ -e POSTGRES_DB=curiositi \ -p 5432:5432 \ pgvector/pgvector:pg16Verify pgvector:
psql -h localhost -U postgres -d curiositi -c "CREATE EXTENSION IF NOT EXISTS vector;"MinIO (S3-compatible local storage)
Section titled “MinIO (S3-compatible local storage)”Docker:
docker run -d \ --name curiositi-minio \ -p 9000:9000 \ -p 9001:9001 \ -e MINIO_ROOT_USER=minioadmin \ -e MINIO_ROOT_PASSWORD=minioadmin \ minio/minio server /data --console-address ":9001"Create bucket:
mc alias set local http://localhost:9000 minioadmin minioadminmc mb local/curiositi-devbunqueue (Local Queue)
Section titled “bunqueue (Local Queue)”For local development without Upstash QStash, you can use bunqueue - a lightweight queue built on Bun.
Start the bunqueue server:
# Using the queue package dev scriptcd packages/queue && bun run dev
# Or run directlybunx bunqueue start --port 6789 --data-path ./queue.dbConfigure environment:
QUEUE_PROVIDER=localBUNQUEUE_HOST=localhostBUNQUEUE_PORT=6789The bunqueue server stores jobs in a local SQLite database (queue.db). Add the following to .gitignore:
queue.dbqueue.db-shmqueue.db-walTroubleshooting Configuration
Section titled “Troubleshooting Configuration”Database Connection Failed
Section titled “Database Connection Failed”# Test connectionpsql $POSTGRES_URL -c "SELECT 1"
# Check pgvectorpsql $POSTGRES_URL -c "SELECT * FROM pg_extension WHERE extname = 'vector'"S3 Connection Failed
Section titled “S3 Connection Failed”# Test S3 accessaws s3 ls s3://$S3_BUCKET --endpoint-url=$S3_ENDPOINTNext Steps
Section titled “Next Steps”- Getting Started — Run Curiositi with your configuration
- Architecture — Understand the system design
- Roadmap — See upcoming features