Files
OpenMAIC/.env.example
T

610 lines
26 KiB
Bash

# =============================================================================
# OpenMAIC Environment Variables
# Copy this file to .env.local and fill in the values you need.
# All variables are optional — only configure the providers you want to use.
# You can also use server-providers.yml for configuration (see docs).
# =============================================================================
# --- LLM Providers -----------------------------------------------------------
# Format: {PROVIDER}_API_KEY, {PROVIDER}_BASE_URL (optional), {PROVIDER}_MODELS (optional, comma-separated)
OPENAI_API_KEY=
OPENAI_BASE_URL=
OPENAI_MODELS=
# For relays whose non-streaming Chat Completions response is incompatible.
# Forces custom OpenAI base URLs to use Chat Completions and buffers SSE responses.
# Has no effect on the official OpenAI base URL. Disabled by default.
# OPENAI_COMPAT_USE_STREAMING_CHAT=true
# Azure uses deployment names as model IDs.
AZURE_OPENAI_API_KEY=
AZURE_OPENAI_BASE_URL=https://YOUR-RESOURCE.openai.azure.com/openai
AZURE_OPENAI_MODELS=
ATLASCLOUD_API_KEY=
ATLASCLOUD_BASE_URL=https://api.atlascloud.ai/v1
# Example: qwen/qwen3.5-flash,deepseek-ai/deepseek-v4-pro
ATLASCLOUD_MODELS=
ANTHROPIC_API_KEY=
ANTHROPIC_BASE_URL=
ANTHROPIC_MODELS=
GOOGLE_API_KEY=
GOOGLE_BASE_URL=
GOOGLE_MODELS=
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=
# Example: deepseek-v4-pro,deepseek-v4-flash,deepseek-v4-flash-vision-exp
DEEPSEEK_MODELS=
QWEN_API_KEY=
QWEN_BASE_URL=
QWEN_MODELS=
KIMI_API_KEY=
KIMI_BASE_URL=
KIMI_MODELS=
MINIMAX_API_KEY=
# MiniMax Anthropic-compatible endpoint for the built-in Anthropic SDK integration
MINIMAX_BASE_URL=https://api.minimaxi.com/anthropic/v1
# Example: MiniMax-M2.7-highspeed,MiniMax-M2.7,MiniMax-M2.5-highspeed,MiniMax-M2.5
MINIMAX_MODELS=
GLM_API_KEY=
GLM_BASE_URL=
GLM_MODELS=
SILICONFLOW_API_KEY=
SILICONFLOW_BASE_URL=
SILICONFLOW_MODELS=
DOUBAO_API_KEY=
DOUBAO_BASE_URL=
DOUBAO_MODELS=
OPENROUTER_API_KEY=
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
# Example: deepseek/deepseek-v4-pro,deepseek/deepseek-v4-flash
OPENROUTER_MODELS=
GROK_API_KEY=
GROK_BASE_URL=
# Example: grok-4.6,grok-4.5
GROK_MODELS=
TENCENT_API_KEY=
# Tencent TokenHub OpenAI-compatible endpoint. Hy3 is a model ID, not an env prefix.
# TENCENT_HUNYUAN_* is also accepted as an alias.
TENCENT_BASE_URL=https://tokenhub.tencentmaas.com/v1
# Example: hy3-preview,hunyuan-2.0-thinking-20251109,hunyuan-2.0-instruct-20251111
TENCENT_MODELS=
XIAOMI_API_KEY=
# MIMO_* is also accepted as an alias. Use tp-... keys only with Token Plan URLs.
XIAOMI_BASE_URL=https://api.xiaomimimo.com/v1
# Token Plan regional examples:
# XIAOMI_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
# XIAOMI_BASE_URL=https://token-plan-sgp.xiaomimimo.com/v1
# XIAOMI_BASE_URL=https://token-plan-ams.xiaomimimo.com/v1
# Example: mimo-v2.5-pro,mimo-v2-pro,mimo-v2.5,mimo-v2-omni,mimo-v2-flash
XIAOMI_MODELS=
TOKENDANCE_API_KEY=
# OpenAI-compatible gateway. The same key also works for the image, video, TTS
# and web-search routes on this host (see the README quick example).
TOKENDANCE_BASE_URL=https://tokendance.space/gateway/v1
# Example: deepseek-v4.1-flash,deepseek-v4-pro,glm-5.3,kimi-k3,qwen3.8-max
TOKENDANCE_MODELS=
# --- Ollama (Local Models) ---------------------------------------------------
# No API key needed. Configure BASE_URL here (server-side) so it bypasses SSRF
# protection automatically. Client-supplied localhost URLs are blocked in production.
# OLLAMA_BASE_URL=http://localhost:11434/v1
# OLLAMA_MODELS=llama3.3,llama3.2,qwen2.5,mistral,gemma3
# Lemonade local server (OpenAI-compatible, no API key required)
# LEMONADE_BASE_URL=http://localhost:13305/v1
# LEMONADE_MODELS=Qwen3-0.6B-GGUF,Llama-3.2-1B-Instruct-Hybrid,Qwen2.5-VL-7B-Instruct
# Amazon Bedrock LLMs (no OpenAI-style API key required)
# Set BEDROCK_REGION to enable Bedrock server-side provider config.
# AWS credentials are resolved from the standard AWS environment / credential chain.
# BEDROCK_REGION=us-east-1
# BEDROCK_MODELS=us.anthropic.claude-sonnet-5,us.anthropic.claude-opus-4-8
# Optional bearer-token authentication or custom Bedrock-compatible endpoint.
# AWS_BEARER_TOKEN_BEDROCK=
# BEDROCK_API_KEY=
# BEDROCK_BASE_URL=
# DEFAULT_MODEL=bedrock:us.anthropic.claude-sonnet-5
# --- TTS (Text-to-Speech) ----------------------------------------------------
TTS_OPENAI_API_KEY=
TTS_OPENAI_BASE_URL=
TTS_AZURE_API_KEY=
TTS_AZURE_BASE_URL=
TTS_GLM_API_KEY=
TTS_GLM_BASE_URL=
TTS_QWEN_API_KEY=
TTS_QWEN_BASE_URL=
# Qwen voice cloning reuses TTS_QWEN_API_KEY. Override the target model if needed.
# TTS_QWEN_VOICE_CLONE_MODEL=qwen3-tts-vc-2026-01-22
TTS_DOUBAO_API_KEY=
TTS_DOUBAO_BASE_URL=
TTS_MINIMAX_API_KEY=
# MiniMax TTS endpoint (speech-2.8 / 2.6 / 02 / 01 series)
TTS_MINIMAX_BASE_URL=https://api.minimaxi.com
TTS_ELEVENLABS_API_KEY=
TTS_ELEVENLABS_BASE_URL=
# VoxCPM2 TTS (local, OpenAI-compatible; API key is optional)
# TTS_VOXCPM_API_KEY=
# TTS_VOXCPM_BASE_URL=http://localhost:8000/v1
# Lemonade TTS (local, no API key required)
# TTS_LEMONADE_BASE_URL=http://localhost:13305/v1
# Operators can force-disable any built-in TTS provider. Examples:
# TTS_OPENAI_ENABLED=false
# TTS_BROWSER_NATIVE_ENABLED=false
# --- ASR (Automatic Speech Recognition) --------------------------------------
ASR_OPENAI_API_KEY=
ASR_OPENAI_BASE_URL=
ASR_QWEN_API_KEY=
ASR_QWEN_BASE_URL=
ASR_AZURE_API_KEY=
ASR_AZURE_BASE_URL=https://{region}.api.cognitive.microsoft.com
# FunASR (local, WAV input only, no API key required)
# ASR_FUNASR_BASE_URL=http://localhost:8000/v1
# Lemonade ASR (local, WAV input only, no API key required)
# ASR_LEMONADE_BASE_URL=http://localhost:13305/v1
# Operators can force-disable any built-in ASR provider. Examples:
# ASR_OPENAI_ENABLED=false
# ASR_BROWSER_NATIVE_ENABLED=false
# Optional local audio/video material extraction uses the first enabled server
# ASR provider above. It also requires the system `ffmpeg` and `ffprobe`
# executables on PATH; no bundled binary or npm dependency is installed.
# Without both executables, OpenMAIC skips the local extractor and uses a
# configured AliDocMind cloud extractor when available. With neither path
# enabled, media materials fail cleanly with setup guidance.
# --- PDF Processing -----------------------------------------------------------
PDF_UNPDF_API_KEY=
PDF_UNPDF_BASE_URL=
PDF_MINERU_API_KEY=
PDF_MINERU_BASE_URL=
# Optional. Defaults to "pipeline"; use "hybrid-auto-engine" only when your MinerU
# service has the required GPU/device configuration.
PDF_MINERU_BACKEND=
PDF_MINERU_CLOUD_API_KEY=
PDF_MINERU_CLOUD_BASE_URL=https://mineru.net/api/v4
# Self-hosted MinerU never falls back to MinerU Cloud implicitly: a request that
# selects self-hosted MinerU without a configured base URL fails loudly. Set this
# to "true" to explicitly opt in to MinerU Cloud as a fallback (documents then
# leave your infrastructure). Default: off.
ALLOW_MINERU_CLOUD_FALLBACK=
# AliDocMind uses an Alibaba Cloud AccessKey pair instead of a single API key.
ALIDOCMIND_ACCESS_KEY_ID=
ALIDOCMIND_ACCESS_KEY_SECRET=
ALIDOCMIND_BASE_URL=
# --- Image Generation ---------------------------------------------------------
IMAGE_OPENAI_API_KEY=
IMAGE_OPENAI_BASE_URL=https://api.openai.com/v1
IMAGE_SEEDREAM_API_KEY=
IMAGE_SEEDREAM_BASE_URL=
IMAGE_QWEN_IMAGE_API_KEY=
IMAGE_QWEN_IMAGE_BASE_URL=
IMAGE_NANO_BANANA_API_KEY=
IMAGE_NANO_BANANA_BASE_URL=
IMAGE_MINIMAX_API_KEY=
# Example models: image-01, image-01-live
IMAGE_MINIMAX_BASE_URL=https://api.minimaxi.com
IMAGE_GROK_API_KEY=
IMAGE_GROK_BASE_URL=
# OpenRouter image generation. Optional; read at runtime. One key reaches every
# image model OpenRouter hosts (FLUX, Seedream, GPT Image, Gemini, Qwen Image,
# Recraft, Krea, ...). The model list in Settings is fetched live from
# GET /images/models, so no model id is pinned here. Base URL defaults to
# https://openrouter.ai/api/v1 when left blank.
IMAGE_OPENROUTER_API_KEY=
IMAGE_OPENROUTER_BASE_URL=
# Lemonade image generation (local, no API key required)
# IMAGE_LEMONADE_BASE_URL=http://localhost:13305/v1
# Operators can force-disable any built-in image provider, including the
# client-only ComfyUI provider (it has no credential env). Examples:
# IMAGE_OPENAI_ENABLED=false
# IMAGE_COMFYUI_ENABLED=false
# --- Video Generation ---------------------------------------------------------
VIDEO_SEEDANCE_API_KEY=
VIDEO_SEEDANCE_BASE_URL=
VIDEO_KLING_API_KEY=
VIDEO_KLING_BASE_URL=
VIDEO_VEO_API_KEY=
VIDEO_VEO_BASE_URL=
VIDEO_SORA_API_KEY=
VIDEO_SORA_BASE_URL=
VIDEO_MINIMAX_API_KEY=
# Example models: MiniMax-Hailuo-2.3, MiniMax-Hailuo-2.3-Fast, MiniMax-Hailuo-02
VIDEO_MINIMAX_BASE_URL=https://api.minimaxi.com
VIDEO_GROK_API_KEY=
VIDEO_GROK_BASE_URL=
VIDEO_HAPPYHORSE_API_KEY=
VIDEO_HAPPYHORSE_BASE_URL=https://dashscope.aliyuncs.com
# OpenRouter video generation. Optional; read at runtime. One key reaches every
# video model OpenRouter hosts (Veo, Kling, Runway, Seedance, Hailuo, Wan,
# Sora, Grok Imagine, ...). The model list in Settings is fetched live from
# GET /videos/models, so no model id is pinned here. Base URL defaults to
# https://openrouter.ai/api/v1 when left blank.
VIDEO_OPENROUTER_API_KEY=
VIDEO_OPENROUTER_BASE_URL=
# Operators can force-disable any built-in video provider. Examples:
# VIDEO_GROK_ENABLED=false
# VIDEO_KLING_ENABLED=false
# --- Web Search ---------------------------------------------------------------
# Note: Grok (xAI) web search is available via chat completions + search tools,
# not as a standalone search API. Use Grok LLM provider with search_parameters
# in chat requests. See: https://docs.x.ai/docs/guides/tools/search-tools
TAVILY_API_KEY=
TAVILY_BASE_URL=
EXA_API_KEY=
EXA_BASE_URL=https://api.exa.ai
BOCHA_API_KEY=
BOCHA_BASE_URL=https://api.bocha.cn
BRAVE_API_KEY=
BRAVE_BASE_URL=
BAIDU_API_KEY=
BAIDU_BASE_URL=https://qianfan.baidubce.com
# Self-hosted SearXNG instance (no API key required)
SEARXNG_BASE_URL=
# Dedicated MiniMax web-search vars avoid conflicting with the LLM MINIMAX_* endpoint.
WEB_SEARCH_MINIMAX_API_KEY=
WEB_SEARCH_MINIMAX_BASE_URL=https://api.minimaxi.com
# Dedicated Doubao web-search vars avoid conflicting with the Doubao LLM provider.
WEB_SEARCH_DOUBAO_API_KEY=
WEB_SEARCH_DOUBAO_BASE_URL=https://open.feedcoopapi.com
# Claude (Anthropic) native web search. Dedicated vars avoid conflicting with
# ANTHROPIC_* LLM provider vars. Optional WEB_SEARCH_CLAUDE_MODELS pins the
# search model server-side (first entry wins), e.g. claude-sonnet-5.
WEB_SEARCH_CLAUDE_API_KEY=
WEB_SEARCH_CLAUDE_BASE_URL=https://api.anthropic.com/v1
WEB_SEARCH_CLAUDE_MODELS=
# Operators can force-disable any built-in web search provider. Examples:
# TAVILY_ENABLED=false
# EXA_ENABLED=false
# WEB_SEARCH_DOUBAO_ENABLED=false
# SEARXNG_ENABLED=false
# Server-only, default-OFF selector for the Native Child execution harness.
# OPENMAIC_ENABLE_PI_NATIVE_CHILD_RUNTIME=true
# Server-only, default-OFF Native Spotlight capability; does not select the runtime.
# OPENMAIC_ENABLE_PI_NATIVE_CHILD_SPOTLIGHT=true
# --- Experimental Features ---------------------------------------------------
# Boolean feature flags accept "true" or "1". NEXT_PUBLIC_* values are compiled
# into the browser bundle at build time, so changing them requires a rebuild.
# Enable the Pro workbench entry (the workbench also requires the agent
# runtime to be configured server-side; see the Agent Runtime section).
# Implies the MAIC Editor gate below — Pro mode always ships with the editor.
# NEXT_PUBLIC_PRO_WORKBENCH_ENABLED=true
# Master gate for the MAIC Editor Pro-mode entry point. Implied by
# NEXT_PUBLIC_PRO_WORKBENCH_ENABLED; set it alone to enable the classroom
# editor on a deployment without the workbench.
# NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true
# Select @openmaic/editor inside Pro mode. This does not enable Pro mode by itself.
# NEXT_PUBLIC_MAIC_EDITOR_RENDERER_ENABLED=true
# Use @openmaic/renderer for the classroom playback canvas.
# NEXT_PUBLIC_MAIC_PLAYBACK_RENDERER_ENABLED=true
# Use the experimental Pi-based classroom chat runtime. Disabled by default.
# NEXT_PUBLIC_PI_CHAT_ENABLED=true
# Enable the unified PPT/Interactive courseware-reference entry in Pi playback.
# Pi chat and editor element references remain independent from this default-off build-time gate.
# Changing a NEXT_PUBLIC_* value requires rebuilding the application.
# NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true
# Enable the server-side vocational task-engine generation path.
# OPENMAIC_ENABLE_VOCATIONAL=true
# Show the experimental vocational task-engine control in the client.
# NEXT_PUBLIC_SHOW_VOCATIONAL_TEST_UI=true
# Show the video export and PPTX import entry points.
# NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true
# NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true
# Informational destination shown on exported Quiz/PBL cover cards. Unset or
# blank defaults to open.maic.chat; set to "off" to omit it.
# NEXT_PUBLIC_VIDEO_EXPORT_CTA_DESTINATION=open.maic.chat
# --- Agent Runtime (experimental) ---------------------------------------------
# Server-only gate for durable background agent sessions: the /api/agent
# session and owner-event control-plane routes plus the in-process session
# runner. Default OFF — while disabled, every /api/agent/sessions* and
# /api/agent/owner-events route answers 404. Truthy values are "true" or "1";
# anything else (including unset) is treated as disabled.
# OPENMAIC_AGENT_RUNTIME_ENABLED=true
# The runtime is server-backed and requires the PostgreSQL connection from the
# "Server-backed Persistence" section below: without a non-empty DATABASE_URL
# the runner never starts and the session store rejects requests, even with the
# flag above enabled.
# DATABASE_URL=postgres://openmaic:password@postgres:5432/openmaic
# REQUIRED while the runtime is enabled: MODEL_ROUTES must explicitly route the
# "maic-agent-driver" stage to a provider-prefixed model id. There is
# intentionally no fallback — without this route every agent session fails at
# run start. The route object must set api (or its alias dialect) to
# "openai-completions" or "openai-responses"; any other value is rejected, and
# a bare model id without a provider prefix is rejected too. Optional fields:
# contextWindow pins the effective context window below the provider catalog
# value (used by compaction thresholds), and thinking must never set effort
# (the tool-using driver cannot combine reasoning_effort with function tools on
# this transport).
# MODEL_ROUTES='{"maic-agent-driver":{"model":"openai:gpt-5.5","api":"openai-completions"}}'
# Runner tuning. Defaults are shown; only relevant once the runtime is enabled.
# OPENMAIC_AGENT_RUNTIME_SCAN_INTERVAL_MS=1000
# OPENMAIC_AGENT_RUNTIME_HEARTBEAT_MS=2000
# OPENMAIC_AGENT_RUNTIME_LEASE_TTL_MS=10000
# OPENMAIC_AGENT_RUNTIME_MAX_CONCURRENT=2
# OPENMAIC_AGENT_RUNTIME_MAX_ATTEMPTS=5
# Global per-tool-call execution bound for every agent run (ms). A tool call
# that neither resolves nor rejects within the budget is aborted and settles as
# an error tool-result the agent can retry or proceed from; the session does
# not die. Default 600000 (10 minutes). Tools with known longer budgets (media
# synthesis, material extraction) carry their own explicit bounds in code.
# OPENMAIC_AGENT_TOOL_TIMEOUT_MS=600000
# Conversation compaction is reserved and OFF by default. The reusable
# compaction runtime is not implemented yet — it lands in a later slice of
# work — and until then the runner runs without context transformation, so
# these knobs are inert placeholders.
# OPENMAIC_AGENT_COMPACTION_ENABLED=true
# OPENMAIC_AGENT_COMPACTION_RESERVE_TOKENS=0
# OPENMAIC_AGENT_COMPACTION_KEEP_RECENT_TOKENS=0
# Session prompts and follow-up messages are capped server-side at a fixed
# 100,000 characters; this limit is a constant and is not configurable.
# --- Proxy (optional) --------------------------------------------------------
# HTTP_PROXY=
# HTTPS_PROXY=
# Comma-separated hosts that bypass the proxy. Supports domain suffixes and *.
# NO_PROXY=localhost,127.0.0.1,.internal.example.com
# --- Misc ---------------------------------------------------------------------
# Server-side default model for API routes like /api/generate-classroom.
# Required for server-side stages (those that don't receive a client x-model):
# resolveModel throws if a stage resolves to no model (no MODEL_ROUTES entry, no
# x-model, no DEFAULT_MODEL) — there is intentionally no hardcoded vendor fallback.
# Example: anthropic:claude-3-5-haiku-20241022 or google:gemini-3-flash-preview
# OpenAI example: openai:gpt-5.5
# MiniMax example: minimax:MiniMax-M2.7-highspeed
# Bedrock example: bedrock:us.anthropic.claude-sonnet-5
DEFAULT_MODEL=
# Optional per-stage model routing (#745). A JSON object mapping a generation
# stage to a model string (`provider:model`). For most stages, resolution order
# is stage route > x-model (client) > DEFAULT_MODEL. A configured route is the
# operator's deliberate choice and wins even when the browser sends its saved
# model as x-model. `conversation-title` is the exception: when unconfigured it
# reuses the exact `maic-agent-driver` connection, never x-model or DEFAULT_MODEL,
# and keeps thinking disabled unless its own route explicitly enables it.
# At boot the server validates MODEL_ROUTES / DEFAULT_MODEL / <PREFIX>_MODELS
# and prints [config] warnings for unknown stages, unregistered providers,
# providers with no API key, and bare model ids (which still default to openai
# but are deprecated — write provider:model). Warnings only: the server starts
# regardless, so a bad value is caught here instead of at request time.
# Routable stages: scene-outlines-stream, scene-content, scene-actions,
# agent-profiles, quiz-grade, pbl-chat, pbl-v2-runtime, chat-adapter,
# generate-classroom, web-search-query-rewrite, maic-agent,
# maic-agent-driver, conversation-title.
# scene-content can also be routed per scene type with composite keys:
# scene-content:slide, scene-content:quiz, scene-content:interactive,
# scene-content:pbl. A type falls back to the base scene-content route when it
# has no key of its own (so scene-content:<type> > scene-content > x-model >
# DEFAULT_MODEL).
# pbl-v2-runtime follows the same composite fallback pattern with
# pbl-v2-runtime:instructor, pbl-v2-runtime:open-task, pbl-v2-runtime:evaluate
# and pbl-v2-runtime:simulator, falling back to the base pbl-v2-runtime route.
# maic-agent-driver is REQUIRED when the agent runtime is enabled; see the
# "Agent runtime (experimental)" section for its api/dialect constraints.
# A route value can be a model string, OR an object {"model","thinking"} where
# `thinking` is the full ThinkingConfig: mode (default|disabled|enabled|auto),
# effort (none|minimal|low|medium|high|xhigh|max), level (minimal|low|medium|
# high, Gemini), enabled (bool), budgetTokens (number), excludeReasoningOutput
# (bool). It is normalized per the model's capability. When a stage is routed:
# a set `thinking` wins over the client's thinking; with no `thinking` the routed
# model uses its own default and the client's thinking is dropped. Unrouted
# stages keep the client thinking.
# Example: cheap default, stronger model only for the heavy/conversational stages:
# MODEL_ROUTES='{"scene-content":"openai:gpt-5.4","scene-actions":"openai:gpt-5.4","pbl-chat":"anthropic:claude-sonnet-4","chat-adapter":"anthropic:claude-sonnet-4"}'
# Example: per scene type + pinned thinking (qwen budget, deepseek off):
# MODEL_ROUTES='{"scene-content:interactive":{"model":"qwen:qwen3.7-plus","thinking":{"enabled":true,"budgetTokens":8000}},"scene-content:quiz":{"model":"deepseek:deepseek-v4-pro","thinking":{"enabled":false}}}'
# MODEL_ROUTES=
# LOG_LEVEL=info
# LOG_FORMAT=pretty
# LLM_THINKING_DISABLED=false
# Opt-in parallel scene-content generation (#572). 0/unset = serial (default).
# A value > 1 fetches scene content concurrently (capped at 10); actions + TTS
# stay serial. Leave off if your API key has a low per-key concurrency quota.
# PARALLEL_SCENE_CONCURRENCY=3
# --- Local/Self-hosted Deployment ---------------------------------------------
# Set to "true" to allow private/local network URLs. That covers private
# (RFC1918), loopback, link-local and CGNAT (100.64.0.0/10, used by Tailscale
# and similar overlay networks) targets. Required for self-hosted models like
# Ollama. Do NOT enable on public deployments.
# The known cloud instance-metadata and credential endpoints (169.254.169.254,
# 169.254.170.2, 169.254.170.23, 100.100.100.200, 168.63.129.16, 192.0.0.192,
# fd00:ec2::254, fd00:ec2::23, metadata.google.internal) are blocked with or
# without this flag, as are IANA reserved, multicast and broadcast ranges. That
# is a fixed address list, not a general link-local block, and under the flag a
# hostname whose DNS lookup fails, times out or returns no answer is still
# allowed through.
# ALLOW_LOCAL_NETWORKS=true
# Build-time, space-separated CSP frame-ancestor sources in addition to 'self'.
# Configure only origins you trust to embed OpenMAIC, then rebuild the app. The
# Docker and Compose builds also accept this value as a build argument.
# ALLOWED_FRAME_ANCESTORS=https://partner.example.com
# Optional MP4 render service (issue #866). When set, the in-app "Export Video"
# menu offers one-click MP4 rendering; when unset, it degrades to downloading a
# project ZIP for local CLI rendering. Point this at the isolated render-service
# container (see render-service/ and the "video-export" docker-compose profile).
# This is operator-supplied trusted config: the app forwards uploads to it
# without the SSRF guard, so a private/compose-network target works WITHOUT
# setting ALLOW_LOCAL_NETWORKS.
# RENDER_SERVICE_URL=http://render-service:9000
# Render-service-only opt-in for bounded local chunk execution. These variables
# are read at runtime by the isolated render-service container; the public HTTP
# API is unchanged. Defaults keep the existing in-process renderer.
# RENDER_CHUNK_EXECUTION=false
# RENDER_CHUNK_COUNT=1
# RENDER_CHUNK_WORKERS=1
# RENDER_MAX_PARALLEL_CHUNKS=1
# RENDER_CHUNK_SIZE_FRAMES=0
# RENDER_TARGET_CHUNK_FRAMES=0
# Honor x-forwarded-for / x-real-ip when deriving client identity for both
# render-service admission and access-code verification throttling.
# Enable only behind a trusted reverse proxy that overwrites these headers.
# TRUST_PROXY_HEADERS=true
# --- Server-backed Persistence ------------------------------------------------
# Build-time client switch and shared development token. The public token must
# match PERSISTENCE_DEV_TOKEN. This development-only scheme provides no user
# isolation and must not be used as public-production authentication.
# NEXT_PUBLIC_PERSISTENCE=1
# NEXT_PUBLIC_PERSISTENCE_TOKEN=
# Runtime PostgreSQL connection and matching development token.
# DATABASE_URL=postgres://openmaic:password@postgres:5432/openmaic
# PERSISTENCE_DEV_TOKEN=
# The development authenticator above is refused when NODE_ENV=production
# unless this explicit opt-in is set. It provides no user isolation (the
# learner key is client-supplied), so enabling it in production is only safe
# on a trusted-network, single-user deployment.
# PERSISTENCE_ALLOW_INSECURE_DEV_AUTH=true
# The anonymous owner cookie carries the `Secure` flag in production builds.
# Safari refuses to store `Secure` cookies served over plain http://localhost
# (unlike Chromium/Firefox, it does not special-case localhost), so every
# request mints a fresh anonymous owner and owner-scoped document writes fail
# with 403. Deployments that serve plain HTTP (no TLS) opt out with the exact
# value 0 — any other spelling (false, no) leaves `Secure` on:
# COOKIE_SECURE=0
# Only do this on a trusted network or locally: without `Secure` the cookie
# travels in the clear and can be replayed by anyone on-path (see
# PERSISTENCE_ALLOW_INSECURE_DEV_AUTH above for the same class of tradeoff).
# Store asset bytes in S3 instead of PostgreSQL. Region, endpoint, and credentials
# are resolved through the standard AWS SDK environment / credential chain.
# ASSET_S3_BUCKET=
# Opt into indirect asset byte egress: answer asset byte GETs with a short-lived
# signed S3 URL (a 302, or a JSON descriptor for the packaged client) instead of
# the bytes. Unset or "direct" keeps direct egress (the safe default). Requires
# the object store's CORS to admit this app's origin and expose Content-Type, and
# the signing identity to hold s3:ListBucket on the bucket so a missing key
# answers 404 NoSuchKey rather than 403.
# ASSET_BYTE_EGRESS=redirect
# The asset collector is enabled by default when DATABASE_URL is configured.
# ASSET_COLLECTION_ENABLED=true
# ASSET_COLLECTION_INTERVAL_MS=900000
# ASSET_COLLECTION_GRACE_MS=3600000
# Root directory for the file-backed classroom store: the classroom JSON
# documents plus their generated media/audio. Defaults to <cwd>/data/classrooms.
# This moves ONLY the classrooms — the classroom generation job store is not
# configurable and stays at <cwd>/data/classroom-jobs.
# OPENMAIC_CLASSROOMS_DIR=/var/lib/openmaic/classrooms
# How long an allocated asset stays pending -- stored, but not yet named by any
# document -- before the collector expires it. A client stores bytes first and
# writes the id into the document afterwards, so this window has to outlive a
# whole generation pass plus a write-back that is waiting for its slide to be
# built; the default is one day for that reason. A value that is not a positive
# integer stops the server from starting.
# ASSET_PENDING_TTL_MS=86400000
# --- Access Control -----------------------------------------------------------
# Set a password to restrict site access. When set, users must enter this code
# before using the app. Leave empty or remove to disable access control
# (fail-open: middleware lets every request through with no credential).
# Read at runtime. When unset, the server logs a one-time startup warning;
# GET /api/health reports accessCodeConfigured: false. Set this before exposing
# the server to a network. The warning does not prevent local zero-config use.
# Use a long random value (at least 16 characters from a random generator):
# this code is the only secret guarding the deployment. The code is remembered
# in a signed token stored in an HTTP-only cookie for 7 days; the lifetime is
# enforced server-side, so visitors re-verify after it expires.
# ACCESS_CODE=your-secret-code
#
# Verification is rate limited only when TRUST_PROXY_HEADERS=true (see above):
# behind a trusted reverse proxy that overwrites x-forwarded-for / x-real-ip,
# each client is limited to 10 attempts per 60 seconds, and a trusted client's
# successful verification clears its own counter. Without a trusted proxy the
# app cannot attribute a request to a client, so there is no throttle; rely on
# the length and randomness of the code instead.