{"id":"env","relativePath":"env.md","title":"Environment Variables","markdown":"# Environment Variables\n\nThis file documents the active Meta Museum environment-variable surface.\n\n## Core app\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `PORT` | No | `3000` | App listen port in local/dev or production process runners. |\n| `NODE_ENV` | No | runtime-set | Standard Node mode (`development`, `test`, `production`). |\n\n## Storage and database\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `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. |\n| `METAMUSEUM_STORAGE_MODE` | No | auto (`postgres` if `DATABASE_URL` present; else `file`) | Storage mode selector: `file`, `double-write`, `postgres`. |\n\n## GitHub issues/SSE\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `GITHUB_OWNER` | No | repo default | Repository owner for issues inventory fetches. |\n| `GITHUB_REPO` | No | repo default | Repository name for issues inventory fetches. |\n| `ISSUE_POLL_MS` | No | service default | Poll cadence for issue refresh behavior. |\n| `GITHUB_TOKEN` | No | none | Optional authenticated GitHub API access for higher rate limits. |\n\n## Auth.js / GitHub OAuth\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `AUTH_SECRET` | Yes in production | dev fallback (`metamuseum-dev-auth-secret-change-me`) when unset outside production | Auth.js secret for session/JWT security. |\n| `AUTH_GITHUB_ID` | Yes for GitHub sign-in | none | GitHub OAuth app client ID. |\n| `AUTH_GITHUB_SECRET` | Yes for GitHub sign-in | none | GitHub OAuth app client secret. |\n| `AUTH_TRUST_HOST` | Optional | unset | Host trust override for Auth.js in certain deployments. |\n\n## Roles and allowlists\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `MM_RESEARCHER_ALLOWLIST` | No | empty | Comma-separated identities granted `researcher`. |\n| `MM_EDITOR_ALLOWLIST` | No | empty | Comma-separated identities granted `editor`. |\n| `MM_ADMIN_ALLOWLIST` | No | empty | Comma-separated identities granted `admin`. |\n\n## Optional provider keys (as providers require)\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `SMITHSONIAN_API_KEY` | Required for Smithsonian live API mode | none | Smithsonian Open Access API key. |\n| `HARVARD_API_KEY` | Required for Harvard live API mode | none | Harvard Art Museums API key. |\n| `RKD_TRIPLY_TOKEN` | Optional/depends on endpoint policy | none | RKD Triply API bearer token. |\n\n## Validation service\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `VALIDATION_SERVICE_URL` | No | local default | URL for FastAPI validation microservice proxy (`/api/validate`). |\n| `VALIDATION_TIMEOUT_MS` | No | service default | Timeout for validation proxy requests. |\n\n## AG2 worker and bridge\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `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. |\n| `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`. |\n| `METAMUSEUM_AG2_BRIDGE_TIMEOUT_MS` | No | `5000` | Bridge request timeout, clamped by code; timeout returns local review fallback. |\n| `METAMUSEUM_AG2_WORKER_HOST` | No | `127.0.0.1` | Bind host for `services/ag2-worker`; keep loopback or private. |\n| `METAMUSEUM_AG2_WORKER_PORT` | No | `7788` | Bind port for the local AG2 worker. |\n| `METAMUSEUM_AG2_WORKER_MAX_RECORDS` | No | `50` | Maximum records accepted per worker request. |\n| `METAMUSEUM_AG2_WORKER_MAX_COLUMNS` | No | `100` | Maximum mapping columns accepted per worker request. |\n| `METAMUSEUM_AG2_EVAL_TARGET` | No | `local` | Target label for `pnpm ag2:worker:eval`; production requires sign-off. |\n| `METAMUSEUM_AG2_OPERATOR_NAME` | Production eval only | none | Operator identity recorded in AG2 worker eval artifacts. |\n| `METAMUSEUM_AG2_OPERATOR_SIGNED_AT` | Production eval only | none | ISO timestamp for operator sign-off. |\n| `METAMUSEUM_AG2_OPERATOR_SCOPE` | Production eval only | none | Scope/rationale for AG2 bridge enablement sign-off. |\n\n## Launch readiness / observability\n\n| Variable | Required | Default | Purpose |\n|---|---|---|---|\n| `BASE_URL` | Required for launch smoke/SLO commands | `http://localhost:3000` in local scripts | Deployed app URL for smoke, a11y, and k6 SLO commands. |\n| `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. |\n| `METAMUSEUM_UPTIME_PROMETHEUS_URL` | Required when using Prometheus uptime source | none | Prometheus base URL for 30-day public-read uptime queries. |\n| `METAMUSEUM_UPTIME_PROMQL_AVAILABILITY` | No | `avg_over_time(probe_success{job=\"metamuseum-public-read\"}[30d])` | PromQL expression for 30-day availability. |\n| `METAMUSEUM_UPTIME_PROMQL_SAMPLE_COUNT` | No | `count_over_time(probe_success{job=\"metamuseum-public-read\"}[30d])` | PromQL expression for 30-day sample count. |\n| `METAMUSEUM_UPTIME_PROBE_PATHS` | No | `/`, `/api/health`, `/api/activity` | Comma-separated paths for scheduled probe uptime evidence. |\n| `METAMUSEUM_UPTIME_PROBE_TIMEOUT_MS` | No | `5000` | Timeout for public-read probe requests. |\n| `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. |\n| `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. |\n| `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. |\n| `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. |\n| `METAMUSEUM_EVIDENCE_SPARQL_QUERY` | No | k6 script default | Optional GitHub Actions query override copied to `SPARQL_QUERY` for the nightly SPARQL p95 check. |\n| `METAMUSEUM_EVIDENCE_AI_QUERY` | No | `find art records` | Representative deployed `/api/ai/query` prompt used by the nightly evidence workflow before telemetry sync. |\n| `METAMUSEUM_KPI_EVIDENCE_PATH` | No | `monitoring/kpi-evidence.json` | Optional aggregate SOTA §26 KPI evidence file for record-enrichment and reconciliation metrics. |\n| `METAMUSEUM_DEPLOYMENT_TARGET` | No | `staging` | Default target for `pnpm launch:preflight`; allowed values: `staging`, `production`. |\n| `METAMUSEUM_A11Y_EVIDENCE_PATH` | No | `artifacts/launch/a11y-latest.json` | Output path for `pnpm a11y:check` launch-review evidence. |\n| `METAMUSEUM_EXPLORE_SMOKE_EVIDENCE_PATH` | No | `artifacts/launch/explore-smoke-latest.json` | Output path for `pnpm smoke:explore:matrix` launch-review evidence. |\n| `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. |\n| `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. |\n| `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. |\n\n## Notes\n\n- Do not commit secrets in `.env` files.\n- Rotate any legacy OAuth credentials that were previously exposed.\n- For production credential rotation (`AUTH_SECRET`, `AUTH_GITHUB_SECRET`), follow [`docs/ops/auth-credential-rotation.md`](docs/ops/auth-credential-rotation.md).\n- Runtime validation for key env vars is enforced in `src/utils/env.ts`.\n","sections":[{"level":2,"heading":"Core app","anchor":"core-app"},{"level":2,"heading":"Storage and database","anchor":"storage-and-database"},{"level":2,"heading":"GitHub issues/SSE","anchor":"github-issues-sse"},{"level":2,"heading":"Auth.js / GitHub OAuth","anchor":"auth-js-github-oauth"},{"level":2,"heading":"Roles and allowlists","anchor":"roles-and-allowlists"},{"level":2,"heading":"Optional provider keys (as providers require)","anchor":"optional-provider-keys-as-providers-require"},{"level":2,"heading":"Validation service","anchor":"validation-service"},{"level":2,"heading":"AG2 worker and bridge","anchor":"ag2-worker-and-bridge"},{"level":2,"heading":"Launch readiness / observability","anchor":"launch-readiness-observability"},{"level":2,"heading":"Notes","anchor":"notes"}],"html":"<h1 id=\"environment-variables\">Environment Variables</h1>\n<p>This file documents the active Meta Museum environment-variable surface.</p>\n<h2 id=\"core-app\">Core app</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `PORT` | No | `3000` | App listen port in local/dev or production process runners. |</p>\n<p>| `NODE_ENV` | No | runtime-set | Standard Node mode (`development`, `test`, `production`). |</p>\n<h2 id=\"storage-and-database\">Storage and database</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `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. |</p>\n<p>| `METAMUSEUM_STORAGE_MODE` | No | auto (`postgres` if `DATABASE_URL` present; else `file`) | Storage mode selector: `file`, `double-write`, `postgres`. |</p>\n<h2 id=\"github-issues-sse\">GitHub issues/SSE</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `GITHUB_OWNER` | No | repo default | Repository owner for issues inventory fetches. |</p>\n<p>| `GITHUB_REPO` | No | repo default | Repository name for issues inventory fetches. |</p>\n<p>| `ISSUE_POLL_MS` | No | service default | Poll cadence for issue refresh behavior. |</p>\n<p>| `GITHUB_TOKEN` | No | none | Optional authenticated GitHub API access for higher rate limits. |</p>\n<h2 id=\"auth-js-github-oauth\">Auth.js / GitHub OAuth</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `AUTH_SECRET` | Yes in production | dev fallback (`metamuseum-dev-auth-secret-change-me`) when unset outside production | Auth.js secret for session/JWT security. |</p>\n<p>| `AUTH_GITHUB_ID` | Yes for GitHub sign-in | none | GitHub OAuth app client ID. |</p>\n<p>| `AUTH_GITHUB_SECRET` | Yes for GitHub sign-in | none | GitHub OAuth app client secret. |</p>\n<p>| `AUTH_TRUST_HOST` | Optional | unset | Host trust override for Auth.js in certain deployments. |</p>\n<h2 id=\"roles-and-allowlists\">Roles and allowlists</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `MM_RESEARCHER_ALLOWLIST` | No | empty | Comma-separated identities granted `researcher`. |</p>\n<p>| `MM_EDITOR_ALLOWLIST` | No | empty | Comma-separated identities granted `editor`. |</p>\n<p>| `MM_ADMIN_ALLOWLIST` | No | empty | Comma-separated identities granted `admin`. |</p>\n<h2 id=\"optional-provider-keys-as-providers-require\">Optional provider keys (as providers require)</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `SMITHSONIAN_API_KEY` | Required for Smithsonian live API mode | none | Smithsonian Open Access API key. |</p>\n<p>| `HARVARD_API_KEY` | Required for Harvard live API mode | none | Harvard Art Museums API key. |</p>\n<p>| `RKD_TRIPLY_TOKEN` | Optional/depends on endpoint policy | none | RKD Triply API bearer token. |</p>\n<h2 id=\"validation-service\">Validation service</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `VALIDATION_SERVICE_URL` | No | local default | URL for FastAPI validation microservice proxy (`/api/validate`). |</p>\n<p>| `VALIDATION_TIMEOUT_MS` | No | service default | Timeout for validation proxy requests. |</p>\n<h2 id=\"ag2-worker-and-bridge\">AG2 worker and bridge</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `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. |</p>\n<p>| `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`. |</p>\n<p>| `METAMUSEUM_AG2_BRIDGE_TIMEOUT_MS` | No | `5000` | Bridge request timeout, clamped by code; timeout returns local review fallback. |</p>\n<p>| `METAMUSEUM_AG2_WORKER_HOST` | No | `127.0.0.1` | Bind host for `services/ag2-worker`; keep loopback or private. |</p>\n<p>| `METAMUSEUM_AG2_WORKER_PORT` | No | `7788` | Bind port for the local AG2 worker. |</p>\n<p>| `METAMUSEUM_AG2_WORKER_MAX_RECORDS` | No | `50` | Maximum records accepted per worker request. |</p>\n<p>| `METAMUSEUM_AG2_WORKER_MAX_COLUMNS` | No | `100` | Maximum mapping columns accepted per worker request. |</p>\n<p>| `METAMUSEUM_AG2_EVAL_TARGET` | No | `local` | Target label for `pnpm ag2:worker:eval`; production requires sign-off. |</p>\n<p>| `METAMUSEUM_AG2_OPERATOR_NAME` | Production eval only | none | Operator identity recorded in AG2 worker eval artifacts. |</p>\n<p>| `METAMUSEUM_AG2_OPERATOR_SIGNED_AT` | Production eval only | none | ISO timestamp for operator sign-off. |</p>\n<p>| `METAMUSEUM_AG2_OPERATOR_SCOPE` | Production eval only | none | Scope/rationale for AG2 bridge enablement sign-off. |</p>\n<h2 id=\"launch-readiness-observability\">Launch readiness / observability</h2>\n<p>| Variable | Required | Default | Purpose |</p>\n<p>|---|---|---|---|</p>\n<p>| `BASE_URL` | Required for launch smoke/SLO commands | `http://localhost:3000` in local scripts | Deployed app URL for smoke, a11y, and k6 SLO commands. |</p>\n<p>| `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. |</p>\n<p>| `METAMUSEUM_UPTIME_PROMETHEUS_URL` | Required when using Prometheus uptime source | none | Prometheus base URL for 30-day public-read uptime queries. |</p>\n<p>| `METAMUSEUM_UPTIME_PROMQL_AVAILABILITY` | No | `avg_over_time(probe_success{job=&quot;metamuseum-public-read&quot;}[30d])` | PromQL expression for 30-day availability. |</p>\n<p>| `METAMUSEUM_UPTIME_PROMQL_SAMPLE_COUNT` | No | `count_over_time(probe_success{job=&quot;metamuseum-public-read&quot;}[30d])` | PromQL expression for 30-day sample count. |</p>\n<p>| `METAMUSEUM_UPTIME_PROBE_PATHS` | No | `/`, `/api/health`, `/api/activity` | Comma-separated paths for scheduled probe uptime evidence. |</p>\n<p>| `METAMUSEUM_UPTIME_PROBE_TIMEOUT_MS` | No | `5000` | Timeout for public-read probe requests. |</p>\n<p>| `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. |</p>\n<p>| `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. |</p>\n<p>| `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. |</p>\n<p>| `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. |</p>\n<p>| `METAMUSEUM_EVIDENCE_SPARQL_QUERY` | No | k6 script default | Optional GitHub Actions query override copied to `SPARQL_QUERY` for the nightly SPARQL p95 check. |</p>\n<p>| `METAMUSEUM_EVIDENCE_AI_QUERY` | No | `find art records` | Representative deployed `/api/ai/query` prompt used by the nightly evidence workflow before telemetry sync. |</p>\n<p>| `METAMUSEUM_KPI_EVIDENCE_PATH` | No | `monitoring/kpi-evidence.json` | Optional aggregate SOTA §26 KPI evidence file for record-enrichment and reconciliation metrics. |</p>\n<p>| `METAMUSEUM_DEPLOYMENT_TARGET` | No | `staging` | Default target for `pnpm launch:preflight`; allowed values: `staging`, `production`. |</p>\n<p>| `METAMUSEUM_A11Y_EVIDENCE_PATH` | No | `artifacts/launch/a11y-latest.json` | Output path for `pnpm a11y:check` launch-review evidence. |</p>\n<p>| `METAMUSEUM_EXPLORE_SMOKE_EVIDENCE_PATH` | No | `artifacts/launch/explore-smoke-latest.json` | Output path for `pnpm smoke:explore:matrix` launch-review evidence. |</p>\n<p>| `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. |</p>\n<p>| `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. |</p>\n<p>| `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. |</p>\n<h2 id=\"notes\">Notes</h2>\n<ul><li>Do not commit secrets in `.env` files.</li><li>Rotate any legacy OAuth credentials that were previously exposed.</li><li>For production credential rotation (`AUTH_SECRET`, `AUTH_GITHUB_SECRET`), follow `docs/ops/auth-credential-rotation.md`(docs/ops/auth-credential-rotation.md).</li><li>Runtime validation for key env vars is enforced in `src/utils/env.ts`.</li></ul>","updatedAt":"2018-10-20T01:46:40.000Z","checksum":"9c18634cab1ae55285c55c7f29c750f433291c3374eb442798fe5b510b4e2c61","checksumPrefix":"9c18634cab1a","anchorCount":10,"lineCount":107,"rawUrl":"/api/docs/content?path=env.md","htmlUrl":"/docs?doc=env.md","apiUrl":"/api/docs/content?path=env.md"}