Environment Variables
This file documents the active Meta Museum environment-variable surface.
Core app
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `PORT` | No | `3000` | App listen port in local/dev or production process runners. |
| `NODE_ENV` | No | runtime-set | Standard Node mode (`development`, `test`, `production`). |
Storage and database
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `DATABASE_URL` | Required for Postgres mode | none | Postgres connection string for JSONB storage-of-record mode; launch preflight expects `sslmode=verify-full` for Neon/Postgres environments. |
| `METAMUSEUM_STORAGE_MODE` | No | auto (`postgres` if `DATABASE_URL` present; else `file`) | Storage mode selector: `file`, `double-write`, `postgres`. |
GitHub issues/SSE
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `GITHUB_OWNER` | No | repo default | Repository owner for issues inventory fetches. |
| `GITHUB_REPO` | No | repo default | Repository name for issues inventory fetches. |
| `ISSUE_POLL_MS` | No | service default | Poll cadence for issue refresh behavior. |
| `GITHUB_TOKEN` | No | none | Optional authenticated GitHub API access for higher rate limits. |
Auth.js / GitHub OAuth
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `AUTH_SECRET` | Yes in production | dev fallback (`metamuseum-dev-auth-secret-change-me`) when unset outside production | Auth.js secret for session/JWT security. |
| `AUTH_GITHUB_ID` | Yes for GitHub sign-in | none | GitHub OAuth app client ID. |
| `AUTH_GITHUB_SECRET` | Yes for GitHub sign-in | none | GitHub OAuth app client secret. |
| `AUTH_TRUST_HOST` | Optional | unset | Host trust override for Auth.js in certain deployments. |
Roles and allowlists
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `MM_RESEARCHER_ALLOWLIST` | No | empty | Comma-separated identities granted `researcher`. |
| `MM_EDITOR_ALLOWLIST` | No | empty | Comma-separated identities granted `editor`. |
| `MM_ADMIN_ALLOWLIST` | No | empty | Comma-separated identities granted `admin`. |
Optional provider keys (as providers require)
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `SMITHSONIAN_API_KEY` | Required for Smithsonian live API mode | none | Smithsonian Open Access API key. |
| `HARVARD_API_KEY` | Required for Harvard live API mode | none | Harvard Art Museums API key. |
| `RKD_TRIPLY_TOKEN` | Optional/depends on endpoint policy | none | RKD Triply API bearer token. |
Validation service
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `VALIDATION_SERVICE_URL` | No | local default | URL for FastAPI validation microservice proxy (`/api/validate`). |
| `VALIDATION_TIMEOUT_MS` | No | service default | Timeout for validation proxy requests. |
AG2 worker and bridge
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `METAMUSEUM_AG2_BRIDGE_ENABLED` | No | `0` | Enables the internal AG2 bridge for eligible review agents only; keep disabled in production unless the AG2 worker runbook evidence is current. |
| `METAMUSEUM_AG2_BRIDGE_URL` | Required only when bridge is enabled | none | Internal AG2 worker endpoint, usually `http://127.0.0.1:7788/ag2/agents/run`. |
| `METAMUSEUM_AG2_BRIDGE_TIMEOUT_MS` | No | `5000` | Bridge request timeout, clamped by code; timeout returns local review fallback. |
| `METAMUSEUM_AG2_WORKER_HOST` | No | `127.0.0.1` | Bind host for `services/ag2-worker`; keep loopback or private. |
| `METAMUSEUM_AG2_WORKER_PORT` | No | `7788` | Bind port for the local AG2 worker. |
| `METAMUSEUM_AG2_WORKER_MAX_RECORDS` | No | `50` | Maximum records accepted per worker request. |
| `METAMUSEUM_AG2_WORKER_MAX_COLUMNS` | No | `100` | Maximum mapping columns accepted per worker request. |
| `METAMUSEUM_AG2_EVAL_TARGET` | No | `local` | Target label for `pnpm ag2:worker:eval`; production requires sign-off. |
| `METAMUSEUM_AG2_OPERATOR_NAME` | Production eval only | none | Operator identity recorded in AG2 worker eval artifacts. |
| `METAMUSEUM_AG2_OPERATOR_SIGNED_AT` | Production eval only | none | ISO timestamp for operator sign-off. |
| `METAMUSEUM_AG2_OPERATOR_SCOPE` | Production eval only | none | Scope/rationale for AG2 bridge enablement sign-off. |
Launch readiness / observability
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `BASE_URL` | Required for launch smoke/SLO commands | `http://localhost:3000` in local scripts | Deployed app URL for smoke, a11y, and k6 SLO commands. |
| `METAMUSEUM_PUBLIC_READ_BASE_URL` | Required when using probe uptime source | falls back to `BASE_URL` for telemetry sync | Public-read probe base URL for uptime evidence. |
| `METAMUSEUM_UPTIME_PROMETHEUS_URL` | Required when using Prometheus uptime source | none | Prometheus base URL for 30-day public-read uptime queries. |
| `METAMUSEUM_UPTIME_PROMQL_AVAILABILITY` | No | `avg_over_time(probe_success{job="metamuseum-public-read"}[30d])` | PromQL expression for 30-day availability. |
| `METAMUSEUM_UPTIME_PROMQL_SAMPLE_COUNT` | No | `count_over_time(probe_success{job="metamuseum-public-read"}[30d])` | PromQL expression for 30-day sample count. |
| `METAMUSEUM_UPTIME_PROBE_PATHS` | No | `/`, `/api/health`, `/api/activity` | Comma-separated paths for scheduled probe uptime evidence. |
| `METAMUSEUM_UPTIME_PROBE_TIMEOUT_MS` | No | `5000` | Timeout for public-read probe requests. |
| `IIIF_TILE_URL` | Required for launch SLO evidence | local icon fallback in k6 | CDN-backed IIIF tile URL for the SOTA §20.4 tile p95 check. |
| `METAMUSEUM_EVIDENCE_BASE_URL` | Required for deployed-target nightly evidence | none | GitHub Actions variable copied to `BASE_URL` for nightly k6, AI-query telemetry seeding, and adoption proof. |
| `METAMUSEUM_EVIDENCE_IIIF_TILE_URL` | Required for deployed-target nightly SLO evidence | none | GitHub Actions variable copied to `IIIF_TILE_URL` for the nightly IIIF tile p95 check. |
| `METAMUSEUM_EVIDENCE_SPARQL_URL` | Required for deployed-target SPARQL SLO evidence | none | GitHub Actions variable copied to `SPARQL_URL` for the nightly whitelisted SPARQL p95 check. |
| `METAMUSEUM_EVIDENCE_SPARQL_QUERY` | No | k6 script default | Optional GitHub Actions query override copied to `SPARQL_QUERY` for the nightly SPARQL p95 check. |
| `METAMUSEUM_EVIDENCE_AI_QUERY` | No | `find art records` | Representative deployed `/api/ai/query` prompt used by the nightly evidence workflow before telemetry sync. |
| `METAMUSEUM_KPI_EVIDENCE_PATH` | No | `monitoring/kpi-evidence.json` | Optional aggregate SOTA §26 KPI evidence file for record-enrichment and reconciliation metrics. |
| `METAMUSEUM_DEPLOYMENT_TARGET` | No | `staging` | Default target for `pnpm launch:preflight`; allowed values: `staging`, `production`. |
| `METAMUSEUM_A11Y_EVIDENCE_PATH` | No | `artifacts/launch/a11y-latest.json` | Output path for `pnpm a11y:check` launch-review evidence. |
| `METAMUSEUM_EXPLORE_SMOKE_EVIDENCE_PATH` | No | `artifacts/launch/explore-smoke-latest.json` | Output path for `pnpm smoke:explore:matrix` launch-review evidence. |
| `METAMUSEUM_TEST_ROLE_OVERRIDE_TOKEN` | Staging smoke only | none | Enables researcher-role smoke checks; generate/update local `.env` with `pnpm launch:smoke-token`, copy the same value to the staging server and smoke runner, and never set it for production. |
| `METAMUSEUM_ACTIVITY_CONSUMER_ID` | Required for `pnpm activity:adoption:probe` unless `--consumer-id` is passed | none | Partner-owned declared consumer ID sent as `x-linked-art-consumer-id` to prove `/api/activity` adoption. |
| `METAMUSEUM_ACTIVITY_CONSUMER_IDS` | Required for `pnpm activity:adoption:matrix` unless `--consumer-id`/`--consumer-ids` is passed | none | Comma-separated partner-owned declared consumer IDs used to prove the full three-consumer `/api/activity` adoption checkpoint. |
Notes
- Do not commit secrets in `.env` files.
- Rotate any legacy OAuth credentials that were previously exposed.
- For production credential rotation (`AUTH_SECRET`, `AUTH_GITHUB_SECRET`), follow `docs/ops/auth-credential-rotation.md`(docs/ops/auth-credential-rotation.md).
- Runtime validation for key env vars is enforced in `src/utils/env.ts`.