# Copy to .env, fill in, then: set -a; source .env; set +a # --- AI models (OpenRouter) # Any OpenAI-compatible endpoint; key from openrouter.ai/keys. LLM_API_KEY= LLM_BASE_URL=https://openrouter.ai/api/v1 # Models are chosen automatically per task (api/routing.py): low / mid / high tier by complexity, escalating # when a draft fails its checks. All via OpenRouter: # code: DeepSeek V4 Flash -> DeepSeek V4 Pro -> GLM-5.2 # scenes: GLM-5.2 -> Kimi K2.6 (scenes start at mid) # Override either with JSON: CODE_MODELS / SCENE_MODELS (or MODEL_REGISTRY for both), e.g. # CODE_MODELS='[{"id": "...", "tier": "low", "provider": "...", "input_usd_per_m": 0.1, "output_usd_per_m": 0.2}, ...]' # Debugging: the first repair tries a free OpenCode Zen model (not OpenRouter, not billed); if that call fails # the same repair goes to the next paid tier. FREE_DEBUG=true DEBUG_MODEL=opencode/deepseek-v4-flash-free LLM_TIMEOUT=180 # --- Storage (defaults shown) # ROSDIFF_DATA_DIR=./data vector store, cloned sources, interface catalogue # ROSDIFF_LOG_DB=./data/generations.sqlite3 every request/response pair # ROSDIFF_TESTERS_FILE=./testers.yaml API-key allowlist (python -m api.keys) # MENAGERIE_DIR=./data/sources/mujoco_menagerie robot models used to load-test scenes # --- MuJoCo generation MJCF_MAX_ATTEMPTS=3 MJCF_SIM_SECONDS=2.0 VALIDATE_TIMEOUT=60 # --- ROS 2 generation: "opencode" (default) or "direct" (plain chat call, no OpenCode) CODEGEN_BACKEND=opencode OPENCODE_BIN=opencode OPENCODE_TIMEOUT=600 CODE_MAX_ATTEMPTS=3 # 1st draft (paid), free debugger, then a stronger paid repair # --- Prompt enhancement: OpenCode + a free OpenCode Zen model (never OpenRouter, never billed; best effort) PROMPT_ENHANCE=true ENHANCE_MODEL=opencode/deepseek-v4-flash-free ENHANCE_TIMEOUT=90 ZEN_API_KEY= # only if the free Zen model asks for a key (opencode.ai/zen) # --- Simulation runs: POST /simulate/run (disabled until the backend and R2 are configured) SIM_BACKEND=modal # "modal" (default) or "runpod" # Modal: deploy with `modal deploy -m worker.modal_app` (see README). Token from `modal token new`, or: # MODAL_TOKEN_ID= # MODAL_TOKEN_SECRET= MODAL_APP=rosdiff-sim # Read at deploy time by worker/modal_app.py: # MODAL_GPU=T4 # "none" = CPU rendering (cheaper, slower video) # MODAL_MAX_CONTAINERS=2 # runs executing at once; the rest queue # RunPod (only with SIM_BACKEND=runpod) RUNPOD_API_KEY= RUNPOD_ENDPOINT_ID= RUN_EXECUTION_TIMEOUT_S=600 # a job is stopped after this long (Modal: set at deploy time) RUN_MAX_DURATION_S=60 # longest simulation a tester can request RUN_BURST_WARN=10 # log a warning when one tester starts more runs than this in 10 minutes # Hugging Face user/org that LeRobot dataset exports go to (the token itself is the Modal secret rosdiff-hf) HF_NAMESPACE= AUTO_REVIEW=false # true: Cosmos Reason reviews every finished run (~3-4 cents each; needs ENABLE_COSMOS) ISAAC_DAILY_LIMIT=10 # Isaac Sim renders per day, all testers together # --- AI budget in rupees: one pool for the test group, an equal share per tester (OpenRouter-exempt calls # are recorded but not deducted; GPU/CPU jobs use the compute limit below instead) BUDGET_TOTAL_INR=500 BUDGET_PER_USER_INR=125 USD_INR=88 # exchange rate used to convert OpenRouter's dollar costs CONFIRM_ABOVE_INR=10 # ask the tester before a task estimated to cost more than this ADMIN_TESTERS= # comma-separated tester names who see the team budget # --- GPU spend: each job's worst case must fit in the tester's equal share and the team's monthly limit MONTHLY_CREDIT_LIMIT_USD=29.98 # the Modal credit for the month; 0 = no limit COMPUTE_TESTERS=4 # the credit is split equally: 29.98 / 4 = $7.495 per tester # COMPUTE_PER_TESTER_USD= # set to override the equal share STORAGE_LIMIT_GB=9 # all testers together; new jobs wait while R2 holds more (free tier: 10 GB) # JOB_PRICES=t4=0.00019,l4=0.00025,cpu=0.00004,runpod=0.00031 # USD per second of container time # JOB_OVERHEAD_S=45 # billed start-up + idle seconds added to each job # Cloudflare R2 (S3 API token with Object Read & Write on the bucket) R2_ACCOUNT_ID= R2_ACCESS_KEY_ID= R2_SECRET_ACCESS_KEY= R2_BUCKET=rosdiff-runs # Report links: /simulate/report/?token=... (signed with this secret; generate with: openssl rand -hex 32) REPORT_SECRET= PUBLIC_BASE_URL= # e.g. https://rosdiff.example.com (defaults to the host the request came in on) FOXGLOVE_ORG= # optional: your Foxglove organization slug, so testers are prompted into it