Environment Variables

Quick Start - Minimum for Local Development

To get the API and UI running locally, you need a surprisingly small set of variables. Copy .env.example to .env at the repo root and fill in these essentials:

Terminal window
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/autonoma
# Redis
REDIS_URL=redis://localhost:6379
# API server
API_PORT=4000
SCENARIO_ENCRYPTION_KEY=any-string-at-least-1-char
# Google OAuth (create credentials at console.cloud.google.com)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# GitHub OAuth (optional - create an OAuth app at github.com/settings/developers)
GITHUB_CLIENT_ID=your-github-oauth-client-id
GITHUB_CLIENT_SECRET=your-github-oauth-client-secret
# AI model keys (needed for test execution)
GEMINI_API_KEY=your-gemini-key
GROQ_KEY=your-groq-key
OPENROUTER_API_KEY=your-openrouter-key
# S3-compatible storage (can use MinIO locally)
S3_BUCKET=autonoma-local
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin

Everything else has sensible defaults or is optional for local development. The sections below cover every variable in detail.

How Environment Variables Work in This Project

Every app and package defines its environment variables in a dedicated env.ts file using createEnv from @t3-oss/env-core. This gives you:

  • Zod validation at startup - the process crashes immediately if a required variable is missing or malformed, rather than failing mysteriously at runtime.
  • Type safety - env.DATABASE_URL is typed as string, not string | undefined. No more process.env.DATABASE_URL! casts.
  • Composability - packages export their env object, and apps extend them. For example, the API server’s env.ts extends the database, storage, logger, and billing envs, inheriting all their variables.

You should never read process.env directly in application code. Always import from the nearest env.ts:

// Good
import { env } from "./env";
const port = env.API_PORT;
// Bad - bypasses validation
const port = process.env.API_PORT;

The emptyStringAsUndefined: true option is enabled everywhere, so setting a variable to an empty string is treated the same as not setting it at all.

For boolean variables, the codebase uses z.stringbool() which accepts "true", "false", "1", "0", "yes", and "no".


Core API Server

Source: apps/api/src/env.ts

The API server extends the database, storage, logger, and billing environments, so all variables from those sections apply here too.

VariableRequiredDefaultDescription
API_PORTYes-Port the API server listens on. Typically 4000.
INTERNAL_DOMAINNoautonoma.appInternal domain used for routing and service discovery.
ALLOWED_ORIGINSNohttp://localhost:3000Comma-separated list of CORS origins. Must include the frontend URL.
SCENARIO_ENCRYPTION_KEYYes-Key used to encrypt scenario data. Any non-empty string works for local dev.
GOOGLE_CLIENT_IDYes-OAuth 2.0 client ID from Google Cloud Console. Required for user authentication.
GOOGLE_CLIENT_SECRETYes-OAuth 2.0 client secret from Google Cloud Console.
GITHUB_CLIENT_IDNo-Client ID of a GitHub OAuth app, enabling GitHub sign-in. Callback URL: <BETTER_AUTH_URL>/v1/auth/callback/github. Not the same as GITHUB_APP_*.
GITHUB_CLIENT_SECRETNo-Client secret of that GitHub OAuth app. GitHub sign-in is offered only when both this and GITHUB_CLIENT_ID are set.
AGENT_VERSIONNolatestVersion tag for the execution agent. Used when dispatching engine jobs.
POSTHOG_KEYNo-PostHog project API key for server-side analytics. Omit to disable analytics.
POSTHOG_HOSTNohttps://us.i.posthog.comPostHog ingestion endpoint. Override for self-hosted PostHog instances.
OPENROUTER_API_KEYNo-Server-side OpenRouter key the managed LLM proxy (/v1/llm-proxy, planner CLI) forwards requests with. The proxy returns 503 without it.
LLM_PROXY_ENABLEDNofalseMaster switch for the managed LLM proxy. The route mounts only when this and STRIPE_ENABLED are both true, so usage is always metered.
LLM_PROXY_ALLOWED_MODELSNogoogle/gemini-3-flash-previewComma-separated allowlist of OpenRouter model ids the proxy may route. Empty falls back to the default.
REDIS_URLYes-Redis connection string (e.g., redis://localhost:6379). Used for device locking, caching, and pub/sub.
TESTINGNofalseSet to true in test environments. Prevents importing certain modules. Not for general use.
ENGINE_BILLING_SECRETNo-Shared secret for authenticating billing calls from the engine.

Frontend (UI)

Source: apps/ui/src/env.ts

The frontend uses Vite’s import.meta.env and requires the VITE_ prefix for all variables.

VariableRequiredDefaultDescription
VITE_API_URLNohttp://localhost:4000URL of the API server. The frontend makes all tRPC calls to this address.
VITE_INTERNAL_DOMAINNoautonoma.appInternal domain, used for UI routing logic.
VITE_TEMPORAL_URLNo-URL of the Temporal UI. When set, enables links to workflow runs in the dashboard.
VITE_SENTRY_DSNNo-Sentry DSN for frontend error tracking. Omit to disable Sentry in the browser.
VITE_SENTRY_URLNo-Sentry organization URL. Used for linking to Sentry issues from the UI.
VITE_POSTHOG_KEYNo-PostHog project API key for frontend analytics. Omit to disable analytics. PostHog events are proxied through the API server at /rs (feature flags at /flags) to bypass ad blockers.

Database

Source: packages/db/src/env.ts

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection string. Format: postgresql://user:password@host:port/database. Used by Prisma for all database operations.

AI Services

Source: packages/ai/src/env.ts

These keys are required by the execution engines (web and mobile) and any service that runs AI inference. The API server does not run inference itself, so it needs none of them.

VariableRequiredDefaultDescription
GEMINI_API_KEYYes-Google Gemini API key. Used for the primary model (Gemini 3 Flash/Pro), point detection, object detection, and visual condition checking.
GROQ_KEYYes-Groq API key. Used for fast inference with open-source models (e.g., GPT-OSS-120B).
OPENROUTER_API_KEYYes-OpenRouter API key. Provides access to Ministral-8B and serves as a fallback provider for open-source models.

Storage (S3)

Source: packages/storage/src/env.ts

Used for storing screenshots, video recordings, test artifacts, and other binary assets.

VariableRequiredDefaultDescription
S3_BUCKETYes-S3 bucket name for storing artifacts.
S3_REGIONYes-AWS region of the S3 bucket (e.g., us-east-1).
S3_ACCESS_KEY_IDYes-AWS access key ID (or MinIO equivalent) for S3 authentication.
S3_SECRET_ACCESS_KEYYes-AWS secret access key (or MinIO equivalent) for S3 authentication.

Logging and Observability

Source: packages/logger/src/env.ts

VariableRequiredDefaultDescription
NODE_ENVNodevelopmentNode environment. Accepts development, production, or test. Affects log formatting and behavior.
SENTRY_DSNNo-Sentry DSN for backend error tracking and performance monitoring. Omit to disable Sentry.
SENTRY_ENVNoproductionSentry environment tag (e.g., staging, production).
SENTRY_RELEASENounknownSentry release identifier. Typically set to the git SHA or version tag in CI.
DEBUGNo-Debug filter string. When set, enables verbose debug logging for matching namespaces (e.g., autonoma:*).

Billing (Stripe)

Source: packages/billing/src/env.ts

Billing is entirely optional. When STRIPE_ENABLED is false (the default), all billing features are disabled and no other Stripe variables are needed.

VariableRequiredDefaultDescription
STRIPE_ENABLEDNofalseMaster switch for billing. Set to true to enable Stripe integration.
STRIPE_SECRET_KEYNo-Stripe secret API key. Required when STRIPE_ENABLED is true.
STRIPE_WEBHOOK_SECRETNo-Stripe webhook signing secret for verifying incoming webhook events. Required when STRIPE_ENABLED is true.
STRIPE_SUBSCRIPTION_PRICE_IDNo-Stripe Price ID for the subscription plan. Required when STRIPE_ENABLED is true.
STRIPE_TOPUP_PRICE_IDNo-Stripe Price ID for credit top-up purchases. Required when STRIPE_ENABLED is true.
BILLING_GRACE_PERIOD_DAYSNo3Number of days after a subscription lapses before access is revoked.
APP_URLNohttp://localhost:3000Frontend application URL. Used in Stripe checkout redirect URLs and billing emails.

Kubernetes and Workflows

Source: packages/k8s/src/env.ts and packages/workflow/src/env.ts

These variables are only needed in production or when running engine jobs on Kubernetes. Not required for local development.

VariableRequiredDefaultDescription
NAMESPACEYes (in K8s)local (API)Kubernetes namespace this environment runs in - production, beta, or a per-PR alpha namespace. Used by @autonoma/k8s to deploy jobs, and by the API to namespace session keys. See the warning below.

The workflow package also reads:

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection string. The workflow package needs direct DB access for job coordination.
SENTRY_ENVNo-Sentry environment tag for workflow jobs.

Engine - Web (Playwright)

Source: packages/engine-web/src/platform/env.ts and packages/engine-web/src/execution-agent/env.ts

The web engine extends the AI, database, logger, and storage environments. All variables from those sections apply.

VariableRequiredDefaultDescription
REMOTE_BROWSER_URLNo-WebSocket URL of a remote browser instance (e.g., Browserless or Playwright remote). When omitted, launches a local Chromium browser.
HEADLESSNo-Set to any value to run Playwright in headless mode. When omitted, the browser window is visible (useful for local debugging).

Engine - Mobile (Appium)

Source: packages/engine-mobile/src/platform/env.ts

The mobile engine extends the AI, database, logger, and storage environments. All variables from those sections apply.

VariableRequiredDefaultDescription
APPIUM_HOSTNo-Hostname of the Appium server.
APPIUM_PORTNo-Port of the Appium server.
APPIUM_MJPEG_PORTNo-Port for the Appium MJPEG video stream. Used for live frame capture during test execution.
APPIUM_SYSTEM_PORTNo-System port used by Appium’s UiAutomator2 (Android) or WebDriverAgent (iOS).
APPIUM_SKIP_INSTALLATIONNotrueWhen true, skips reinstalling the app before each test. Speeds up repeated runs on the same device.
DEVICE_NAMENo-Name of the target device or emulator (e.g., iPhone 15 Pro, Pixel 7).
IOS_PLATFORM_VERSIONNo-iOS version to target (e.g., 17.2). Required for iOS testing.
ANDROID_DAEMON_HOSTSNo-Comma-separated list of Android daemon host addresses for distributed device access.
IOS_DAEMON_HOSTSNo-Comma-separated list of iOS daemon host addresses for distributed device access.
SKIP_DEVICE_DATE_UPDATENofalseWhen true, skips updating the device date/time before tests. Useful when the device clock is already correct.

Jobs

Execution Agent Runner

Source: packages/engine/src/execution-agent/runner/env.ts

VariableRequiredDefaultDescription
ARTIFACT_DIRNo-Local directory for saving test artifacts (screenshots, videos, step logs). Used by the local runner during development.

Run Completion Notification

Source: apps/jobs/run-completion-notification/src/env.ts

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection string.
API_URLNo-API server URL for callbacks.
ENGINE_BILLING_SECRETNo-Shared secret for authenticating billing-related calls.
STRIPE_ENABLEDNofalseWhether to process billing events on run completion.

Worker - Diffs

Source: apps/workers/diffs/src/env.ts

Diffs analysis and resolution run as Temporal activities in the @autonoma/worker-diffs worker. AI model keys come from the AI Services section; this worker adds the GitHub App credentials it needs to clone repositories and read PRs.

VariableRequiredDefaultDescription
GITHUB_APP_IDYes-GitHub App ID for repository access.
GITHUB_APP_PRIVATE_KEYYes-GitHub App private key, base64-encoded PEM (cat key.pem | base64).
GITHUB_APP_WEBHOOK_SECRETYes-GitHub App webhook secret for verifying events.
GITHUB_APP_SLUGYes-GitHub App slug (URL-friendly name).
SENTRY_DSN_WORKER_DIFFSNo-Sentry DSN for the diffs worker.

GitHub App

These variables appear in .env.example and are used by the API server and the diffs worker for GitHub integration features (repository connections, PR-triggered test runs).

VariableRequiredDefaultDescription
GITHUB_APP_IDNo-GitHub App ID. Required for GitHub integration features.
GITHUB_APP_PRIVATE_KEYNo-GitHub App private key, base64-encoded PEM (cat key.pem | base64). Decoded at boot.
GITHUB_APP_WEBHOOK_SECRETNo-Secret for verifying GitHub webhook payloads.
GITHUB_APP_SLUGNo-GitHub App slug (URL-friendly name). Used for generating installation links.

Authentication

These variables are referenced in .env.example for the Better Auth integration used by the API server.

VariableRequiredDefaultDescription
BETTER_AUTH_SECRETYes-Secret key for Better Auth session signing. Generate with openssl rand -hex 32.
BETTER_AUTH_URLYes-Root origin of the API server (e.g., http://localhost:4000). Used by Better Auth for callback URLs. Origin only - see the warning below.
OAUTH_PROXY_PRODUCTION_URLNo-The one origin whose OAuth callback is registered with the providers, for the whole fleet. Every deployed environment sets the same value. Leave unset locally.
OAUTH_PROXY_SECRETNoBETTER_AUTH_SECRETEncrypts the profile payload the proxy hands back to the originating environment. Every participating environment must share the same value.

OAuth proxying

A provider only redirects to callback URLs registered with it ahead of time, and an alpha environment’s hostname is minted per PR - so it can never be one of them. Instead, every deployed environment sends the provider production’s callback URL and gets the resulting profile handed back, encrypted and short-lived, at its own origin, where it mints its own session. Production’s own APP_URL matches OAUTH_PROXY_PRODUCTION_URL, so it skips proxying and serves the callback for the fleet.

Two things about this are easy to get wrong:

  • Leave both unset locally. Local dev has its own OAuth apps, and enabling the proxy would mean configuring production to hand encrypted session payloads to a developer’s machine.
  • OAUTH_PROXY_PRODUCTION_URL is not a plain on/off switch. Setting it without every participating environment sharing the same OAUTH_PROXY_SECRET breaks sign-in on the non-production environments.

OAUTH_PROXY_SECRET is deliberately separate from BETTER_AUTH_SECRET: it is shared across environments, so a leak must not also be able to forge sessions. It falls back to BETTER_AUTH_SECRET when unset, which works but widens the blast radius.


Tips for Local Development

What you can skip entirely:

  • Billing - Leave STRIPE_ENABLED=false (the default). No Stripe keys needed.
  • Analytics - Omit POSTHOG_KEY and VITE_POSTHOG_KEY. Analytics calls become no-ops.
  • Sentry - Omit SENTRY_DSN and VITE_SENTRY_DSN. Error tracking is disabled gracefully.
  • Kubernetes - Omit NAMESPACE. The API defaults it to local; only @autonoma/k8s needs a real one.
  • OAuth proxying - Omit OAUTH_PROXY_PRODUCTION_URL and OAUTH_PROXY_SECRET. Local dev signs in against its own OAuth apps.
  • GitHub App - Omit all GITHUB_APP_* variables unless you are working on GitHub integration.
  • Temporal - Omit VITE_TEMPORAL_URL. The UI hides workflow links when this is unset.

What uses defaults that just work:

  • ALLOWED_ORIGINS defaults to http://localhost:3000 - correct for local dev.
  • VITE_API_URL defaults to http://localhost:4000 - correct for local dev.
  • APP_URL defaults to http://localhost:3000 - correct for local dev.
  • NODE_ENV defaults to development.
  • AGENT_VERSION defaults to latest.

What you must provide:

  • DATABASE_URL - there is no default. You need a running PostgreSQL instance.
  • REDIS_URL - there is no default. You need a running Redis instance.
  • GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET - required for authentication. Create OAuth credentials in the Google Cloud Console.
  • GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET - optional. Set both to add GitHub as a second sign-in option; see Development Setup for the OAuth app steps.
  • SCENARIO_ENCRYPTION_KEY - any non-empty string works locally.
  • BETTER_AUTH_SECRET - generate one with openssl rand -hex 32.
  • BETTER_AUTH_URL - set to http://localhost:4000. The origin only; appending /v1 404s every auth endpoint.
  • AI keys (GEMINI_API_KEY, GROQ_KEY, OPENROUTER_API_KEY) - required if you are running test execution. Not needed if you are only working on the UI or API without triggering test runs.
  • S3 credentials - required for artifact storage. Use MinIO locally.
Link copied