Browse guides

Environment variables

Every setting the onhr installation reads from its environment, and what each one turns on.

onhr reads its settings from the environment. Locally, put them in .env.local in the project root. On a server, set them in your host's settings.

Who can do this

Anyone running their own copy, on the server they deploy to.

Steps

  1. Start with the two Supabase values. Without them there is no sign-in and no database.
  2. Add the variables for the parts you want to use, from the tables below.
  3. Restart the server after a change.

Never put a secret in a file you commit or share. SUPABASE_SERVICE_ROLE_KEY and every secret below stay on the server and never reach the browser.

Required

VariableWhat it is for
NEXT_PUBLIC_SUPABASE_URLYour Supabase project's URL.
NEXT_PUBLIC_SUPABASE_ANON_KEYYour Supabase project's anon key.

Server work and secrets

VariableWhat it is for
SUPABASE_SERVICE_ROLE_KEYServer-only work: scheduled agents, file clean-ups, reading a workspace's stored keys, and test clean-up. Never expose it to the browser.
AI_KEYS_ENCRYPTION_SECRET32+ characters. Seals each workspace's OpenRouter and Resend keys, and the sessions behind MCP API keys. Without it a workspace cannot save its own keys. It also signs the unsubscribe links in CRM broadcasts, so broadcasts can't send without it. Use the same value on every host: changing it makes stored keys unreadable and breaks the unsubscribe links in broadcasts already sent.
AUTH_COOKIE_SECRETOptional, 32+ characters. Signs the short-lived cookie a password-reset link leaves. Without it the app uses a key made from AI_KEYS_ENCRYPTION_SECRET, or else a random key made when the server starts.
RATE_LIMIT_PEPPERKeys the hashes the rate limiter stores, so they cannot be tested against guesses.

AI

VariableWhat it is for
OPENROUTER_API_KEYOptional. The platform key behind the 3 free questions a week for people whose workspace has no key of its own.
OVERWATCH_MODEL_ORCHESTRATOR, OVERWATCH_MODEL_WORKERThe models for AI Assistant and its specialists, as OpenRouter model ids.
OVERWATCH_MODEL_RECEIPTSThe model that reads receipts in the Receipts Inbox. Without it, the worker model is used.
OVERWATCH_MODEL_AGENT_SEARCH, OVERWATCH_MODEL_AGENT_DIGEST, OVERWATCH_MODEL_AGENT_IMAGE, OVERWATCH_MODEL_AGENT_VIDEOOverride the models for the Weekly Studio agent's steps.
AI_GATEWAY_BASE_URLOptional gateway in front of OpenRouter.

Scheduled jobs and agents

VariableWhat it is for
CRON_SECRET32+ characters. Authorises the scheduled endpoints.
CRON_ALLOW_LEGACY_KEYA temporary switch for installs whose scheduler still sends the service-role key. Set it to false. See Scheduled jobs.
AGENTS_ENABLEDtrue (or 1) lets scheduled agent runs happen. Off by default.

Push notifications

VariableWhat it is for
NEXT_PUBLIC_VAPID_PUBLIC_KEYThe public half of your push key pair. It is sent to browsers.
VAPID_PRIVATE_KEYThe private half. Server-only: never share it or commit it.
VAPID_SUBJECTWho runs this server, as a mailto: address or an https:// address. The push services refuse anything else.

Make the key pair once:

npx web-push generate-vapid-keys

Keep the same pair on every host. A new pair cuts off every device that turned push on. Without all three values, the Notifications page says push isn't set up and the rest of the app works as before. Push is sent by a scheduled job: see Scheduled jobs.

Features and sign-in

VariableWhat it is for
MCP_SIGN_IN_ENABLEDtrue turns on "Sign in with onhr" for MCP apps. Off by default, so AI tools connect with API keys only. See Turn on Sign in with onhr.
NEXT_PUBLIC_DEMO_ENABLED1 shows the Try the demo button on the login page and lets the demo sign-in run. Unset, the demo sign-in answers "Demo is not available."
PUBLIC_SITE_URLThe lasting address written into broadcast unsubscribe links. Without it, the address the request came in on is used.
OVERWATCH_PREVIEW1 serves the sample-data preview from a production build. Read only when the Supabase values are missing.

Tools

VariableWhat it is for
OVERWATCH_SUPABASE_TOKENA Supabase access token, used only by pnpm db:migrate.

Email broadcasts use each workspace's own Resend key, entered in the app, so there is no email variable to set.

Common problems

  • Chat says "Your workspace key could not be used on this server. Ask an owner to save it again." The workspace's key was sealed with a different AI_KEYS_ENCRYPTION_SECRET, for example after a move to a new host. Set the old value again. If it is lost, an owner or admin saves the key again on AI key.
  • The scheduled endpoints answer 401. CRON_SECRET is unset, empty or shorter than 32 characters, or the scheduler sends a different value. Or CRON_ALLOW_LEGACY_KEY is false while the scheduler still sends the service-role key.
  • Password-reset links are sometimes refused. You run several instances or a serverless host and set neither AUTH_COOKIE_SECRET nor AI_KEYS_ENCRYPTION_SECRET. Set one of them.