Skip to content

Environment variables

All environment variables required to run Classmoji

NameRequiredDefaultDescription
DATABASE_URLYesPostgreSQL connection string for the Classmoji database. We recommend Neon for production.
BETTER_AUTH_SECRETYesSecret used to sign auth sessions and tokens. Generate with openssl rand -base64 32.
WEBAPP_URLYesPublic base URL of the main web app (e.g. http://localhost:3000).
SLIDES_URLYesPublic base URL of the slides service.
PAGES_URLYesPublic base URL of the pages service.
NameRequiredDefaultDescription
GITHUB_APP_NAMENoSlug of your Github App, used to build install and authorization links.
GITHUB_APP_IDNoNumeric ID of your Github App.
GITHUB_CLIENT_IDNoOAuth client ID for Github sign-in.
GITHUB_CLIENT_SECRETNoOAuth client secret for Github sign-in.
GITHUB_WEBHOOK_SECRETNoSecret used to verify incoming Github webhook signatures. Generate with openssl rand -base64 32.
GITHUB_PRIVATE_KEY_BASE64NoBase64-encoded private key for your Github App, used to authenticate API requests.

AI features (quizzes, Ask Moji) run on Anthropic Claude. They are optional: when AI_AGENT_URL and AI_AGENT_SHARED_SECRET are unset, AI features that run on the AI agent are hidden and the related API routes return 503. Ask Moji can instead run as a background-jobs chat agent (ASK_MOJI_RUNTIME=trigger), which needs TRIGGER_SECRET_KEY and an Anthropic key rather than the AI agent.

NameRequiredDefaultDescription
AI_AGENT_URLNoURL of the AI agent service. Enables AI features when set with the shared secret.
AI_AGENT_SHARED_SECRETNoShared secret used to authenticate the webapp to the AI agent.
ANTHROPIC_API_KEYNoAnthropic API key the AI agent uses to call Claude.
LLM_MODELNoclaude-sonnet-5-5Claude model used for quizzes. 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_MODELNoclaude-sonnet-5-5Claude 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_MODENoControls the code-aware exploration behavior for quizzes.
QUIZ_QUESTION_EFFORTNomediumReasoning effort (low, medium, high, xhigh, max) for quiz question and conversation turns. A classroom with its own API key can override it.
QUIZ_GRADING_EFFORTNohighReasoning effort for final quiz grading. A classroom with its own API key can override it.
EXPLORATION_EFFORTNolowReasoning 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.
ASK_MOJI_RUNTIMENoai_agentWhich runtime serves Ask Moji. ai_agent (also when unset): the AI agent, in the web app only. trigger: the ask-moji chat agent on Trigger.dev, in the web app, pages and slides, with the instructor insights page; it needs TRIGGER_SECRET_KEY and an Anthropic key (ANTHROPIC_API_KEY or the classroom’s own). Set it on the web app, pages and slides alike (the pages and slides apps embed the web app’s Ask Moji panel), and on the MCP server: it also gates the MCP server’s Ask Moji tools (usage, feedback review, settings), which work only where Ask Moji does. With trigger, the background jobs also need MCP_PUBLIC_URL. Any value other than trigger or ai_agent runs as ai_agent.
MCP_PUBLIC_URLWith ASK_MOJI_RUNTIME=triggerPublic origin of the MCP server (apps/mcp), for example https://mcp.example.org. The MCP server advertises it to its clients, and Ask Moji reads the course through it: set it on the background jobs too, or Ask Moji can’t answer questions. Use the public HTTPS origin, not a private network hostname.
SYLLABUS_BOT_MODELNoLLM_MODEL, then claude-sonnet-5-5Claude model used for Ask Moji. With ASK_MOJI_RUNTIME=trigger it accepts only the models listed in packages/utils/src/aiModels.ts (any other value runs claude-sonnet-5-5), as LLM_MODEL does; on the AI agent any Claude model id works. Read by the AI agent and the background jobs, and by the web app to show the default. A classroom with its own API key can override it with an allow-listed model.
SYLLABUS_BOT_EFFORTNolowReasoning effort for Ask Moji. A classroom with its own API key can override it.
AI_MAX_BUDGET_USDNo1.00Per-call cost ceiling in USD for quiz and Ask Moji agent calls on the AI agent with the platform ANTHROPIC_API_KEY. A runaway guard, not a spend limit.
OPENAI_API_KEYNoReserved. Not used by any current feature.
LLM_PROVIDERNoReserved. Only Anthropic/Claude is wired today.
NameRequiredDefaultDescription
STRIPE_SECRET_KEYNoStripe secret API key for subscription checkout and billing.
STRIPE_WEBHOOK_SECRETNoSecret used to verify incoming Stripe webhook signatures.
NameRequiredDefaultDescription
EMAILNoAddress used as the sender for outgoing email.
EMAIL_PASSWORDNoPassword (or app password) for the sending email account.
NameRequiredDefaultDescription
TRIGGER_API_URLNoBase URL of the Trigger.dev API. Leave unset to use Trigger.dev cloud.
TRIGGER_PUBLIC_API_URLNoPublic 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_KEYNoTrigger.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.

NameRequiredDefaultDescription
MEDIA_R2_ACCOUNT_IDNoCloudflare account the media bucket lives in. Used to build the R2 S3 endpoint.
MEDIA_R2_ACCESS_KEY_IDNoAccess key of an R2 API token scoped to the media bucket (object read/write).
MEDIA_R2_SECRET_ACCESS_KEYNoSecret of that R2 API token. It never leaves the server: uploads are presigned and the browser writes straight to R2.
MEDIA_R2_BUCKETNoName of the R2 bucket media objects are written to.
CLOUDINARY_CLOUD_NAMENoCloudinary cloud name for image and media uploads.
CLOUDINARY_API_KEYNoCloudinary API key for signed uploads.
CLOUDINARY_API_SECRETNoCloudinary API secret for signed uploads.
NameRequiredDefaultDescription
CALENDAR_SECRETNoSecret used to sign calendar feed (iCal) URLs. Generate with openssl rand -base64 32.