| Name | Required | Default | Description |
|---|
DATABASE_URL | Yes | | PostgreSQL connection string for the Classmoji database. |
BETTER_AUTH_SECRET | Yes | | Secret used to sign auth sessions and tokens. Generate with openssl rand -base64 32. |
WEBAPP_URL | Yes | | Public base URL of the main web app (e.g. http://localhost:3000). |
SLIDES_URL | Yes | | Public base URL of the slides service. |
PAGES_URL | Yes | | Public base URL of the pages service. |
| Name | Required | Default | Description |
|---|
GITHUB_APP_NAME | No | | Slug of your Github App, used to build install and authorization links. |
GITHUB_APP_ID | No | | Numeric ID of your Github App. |
GITHUB_CLIENT_ID | No | | OAuth client ID for Github sign-in. |
GITHUB_CLIENT_SECRET | No | | OAuth client secret for Github sign-in. |
GITHUB_WEBHOOK_SECRET | No | | Secret used to verify incoming Github webhook signatures. Generate with openssl rand -base64 32. |
GITHUB_PRIVATE_KEY_BASE64 | No | | Base64-encoded private key for your Github App, used to authenticate API requests. |
AI features (quizzes, Ask Moji, prompt assistant) run on Anthropic Claude. They are optional: when AI_AGENT_URL and AI_AGENT_SHARED_SECRET are unset, AI features are hidden and the related API routes return 503.
| Name | Required | Default | Description |
|---|
AI_AGENT_URL | No | | URL of the AI agent service. Enables AI features when set with the shared secret. |
AI_AGENT_SHARED_SECRET | No | | Shared secret used to authenticate the webapp to the AI agent. |
ANTHROPIC_API_KEY | No | | Anthropic API key the AI agent uses to call Claude. |
LLM_MODEL | No | claude-sonnet-5-5 | Claude model used for quizzes and the quiz prompt assistant. These accept only the models listed in packages/utils/src/aiModels.ts; any other value runs the default. Set the same value in all three places that read it: the AI agent and the background jobs, which run quizzes, and the web app, which shows it as the default on AI settings. |
EXPLORATION_MODEL | No | claude-sonnet-5-5 | Claude model used for code-aware quiz repository exploration. Same list and default as LLM_MODEL, read by the same three: the AI agent, the background jobs and the web app. |
EXPLORATION_MODE | No | | Controls the code-aware exploration behavior for quizzes. |
QUIZ_QUESTION_EFFORT | No | medium | Reasoning effort (low, medium, high, xhigh, max) for quiz question and conversation turns. A classroom with its own API key can override it. |
QUIZ_GRADING_EFFORT | No | high | Reasoning effort for final quiz grading. A classroom with its own API key can override it. |
EXPLORATION_EFFORT | No | low | Reasoning effort for the code-aware quiz’s excerpt selection (xhigh and max run as high). A classroom with its own API key can override it. |
SYLLABUS_BOT_MODEL | No | LLM_MODEL, then claude-sonnet-5-5 | Claude model used for Ask Moji. Any Claude model id works here; the quiz list does not apply. Read by the AI agent, and by the web app to show the default. A classroom with its own API key can override it. |
SYLLABUS_BOT_EFFORT | No | low | Reasoning effort for Ask Moji. A classroom with its own API key can override it. |
AI_MAX_BUDGET_USD | No | 1.00 | Per-call cost ceiling in USD for quiz and Ask Moji agent calls on the platform ANTHROPIC_API_KEY. A runaway guard, not a spend limit. |
OPENAI_API_KEY | No | | Reserved. Not used by any current feature. |
LLM_PROVIDER | No | | Reserved. Only Anthropic/Claude is wired today. |
| Name | Required | Default | Description |
|---|
STRIPE_SECRET_KEY | No | | Stripe secret API key for subscription checkout and billing. |
STRIPE_WEBHOOK_SECRET | No | | Secret used to verify incoming Stripe webhook signatures. |
| Name | Required | Default | Description |
|---|
EMAIL | No | | Address used as the sender for outgoing email. |
EMAIL_PASSWORD | No | | Password (or app password) for the sending email account. |
| Name | Required | Default | Description |
|---|
TRIGGER_API_URL | No | | Base URL of the Trigger.dev API. Leave unset to use Trigger.dev cloud. |
TRIGGER_PUBLIC_API_URL | No | | Public Trigger.dev API address that GitHub Actions can reach; the generated autograding workflow reports results to it. Leave unset for Trigger.dev cloud. Not the worker-internal TRIGGER_API_URL. |
TRIGGER_SECRET_KEY | No | | Trigger.dev secret key used to authenticate background job runs. |
Large files (video, audio, big PDFs) go to a Cloudflare R2 bucket rather than into a classroom’s content repo. The four MEDIA_R2_* variables are optional and all-or-nothing: with any of them unset, media upload is hidden in the UI and the media API routes return 503.
| Name | Required | Default | Description |
|---|
MEDIA_R2_ACCOUNT_ID | No | | Cloudflare account the media bucket lives in. Used to build the R2 S3 endpoint. |
MEDIA_R2_ACCESS_KEY_ID | No | | Access key of an R2 API token scoped to the media bucket (object read/write). |
MEDIA_R2_SECRET_ACCESS_KEY | No | | Secret of that R2 API token. It never leaves the server: uploads are presigned and the browser writes straight to R2. |
MEDIA_R2_BUCKET | No | | Name of the R2 bucket media objects are written to. |
CLOUDINARY_CLOUD_NAME | No | | Cloudinary cloud name for image and media uploads. |
CLOUDINARY_API_KEY | No | | Cloudinary API key for signed uploads. |
CLOUDINARY_API_SECRET | No | | Cloudinary API secret for signed uploads. |
| Name | Required | Default | Description |
|---|
CALENDAR_SECRET | No | | Secret used to sign calendar feed (iCal) URLs. Generate with openssl rand -base64 32. |