Environment variables·
Generated at every docs build by scripts/envdoc.py, which walks every os.getenv / os.environ in the repo. Purposes come
from scripts/envdoc_notes.py; a variable without a note still gets a row (purpose —) so nothing can go undocumented
silently — tests/test_docs.py asserts that.
Where they are set: your .env (see the walkthrough), the compose files (service-specific overrides),
.tiny-mcp.env for the fleet token, and the cockpit's ⚙️ drawer for live edits of masked keys.
Rover·
| variable | default | read by | purpose |
|---|---|---|---|
ROVER_CONTROLLER_ANGULAR_MAX |
0.9 |
tools/_controller_engine.py |
PS4 teleop: cap on |
ROVER_CONTROLLER_DEADZONE |
0.08 |
tools/_controller_engine.py |
PS4 teleop: stick dead-zone (0.08). |
ROVER_CONTROLLER_DEBUG |
0 |
tools/_controller_engine.py |
1 surfaces pygame/SDL warnings on stderr. |
ROVER_CONTROLLER_HZ |
10 |
tools/_controller_engine.py |
PS4 teleop: /control frames per second while sticks are held. |
ROVER_CONTROLLER_LINEAR_MAX |
0.7 |
tools/_controller_engine.py |
PS4 teleop: cap on |
ROVER_CONTROLLER_LOG |
/tmp/rover_controller_sdl.log |
tools/_controller_engine.py |
Spool file for those warnings. |
ROVER_HTTP_TIMEOUT |
60 |
tools/_rover_common.py |
Seconds before an SDK HTTP call in _rover_common gives up. |
ROVER_SDK_URL |
http://localhost:8002 |
dashboard_server.py, listener_loop.py, media_client.py, media_hub.py, tools/_rover_common.py, voice_agent.py |
Where every tool and the cockpit find the Earth Rovers SDK (http://localhost:8002 locally, http://sdk:8002 in compose). |
ROVER_TURN_SIGN |
1 |
tools/_rover_common.py |
Flip (-1) the agent tools' angular sign if the rover turns the wrong way; independent from the cockpit's DASH_TURN_SIGN. |
SCOUT_ASYNC_FRAME_INTERVAL |
0.35 |
tools/rover_async.py |
rover_async: seconds between /control frames streamed by the background worker (0.35). |
Models·
| variable | default | read by | purpose |
|---|---|---|---|
AWS_REGION |
us-east-1 |
voice_agent.py |
Bedrock region for the text model and Nova Sonic voice. |
C3_GEN_MODEL |
nvidia/Cosmos3-Nano |
docker/warmup.py |
GPU stack: Cosmos 3 generator HF id to pre-download. |
C3_MODEL |
nvidia/Cosmos3-Nano |
docker/warmup.py |
GPU stack: Cosmos 3 reasoner HF id to pre-download (default nvidia/Cosmos3-Nano). |
GEMINI_API_KEY |
(unset) | voice_agent.py |
Alternative to GOOGLE_API_KEY for Gemini Live. |
GOOGLE_API_KEY |
(unset) | voice_agent.py |
Gemini Live key (VOICE_PROVIDER=gemini); GEMINI_API_KEY is the alternative name. |
HF_TOKEN |
(unset) | docker/warmup.py |
Hugging Face token for model downloads during the GPU image warm-up. |
OPENAI_API_KEY |
(unset) | voice_agent.py |
OpenAI Realtime key for VOICE_PROVIDER=openai. |
Voice·
| variable | default | read by | purpose |
|---|---|---|---|
LISTENER_COOLDOWN_SEC |
2 |
listener_loop.py |
Minimum gap between two agent triggers. |
LISTENER_CUDA |
auto |
listener_loop.py |
cpu forces CPU inference; anything else tries CUDA. |
LISTENER_DISABLED |
0 |
listener_loop.py |
1 = the listener loop exits immediately. |
LISTENER_ENERGY_THRESHOLD |
0.012 |
listener_loop.py |
RMS (0..1) above which a frame counts as speech. |
LISTENER_MAX_SEG_SEC |
12 |
listener_loop.py |
Hard cap on a single utterance. |
LISTENER_MIC_RATE |
16000 |
listener_loop.py |
Mic sample rate the listener drains at (16 kHz). |
LISTENER_MIN_CHARS |
4 |
listener_loop.py |
Ignore transcripts shorter than this. |
LISTENER_MIN_SEG_SEC |
0.6 |
listener_loop.py |
Drop segments shorter than this. |
LISTENER_SILENCE_SEC |
0.8 |
listener_loop.py |
Trailing silence that ends an utterance. |
LISTENER_USE_HUB |
1 |
listener_loop.py |
1 (default) reads the mic through the MediaHub instead of draining /rover-mic directly. |
LISTENER_VAD_AGGRESSIVENESS |
2 |
listener_loop.py |
webrtcvad aggressiveness 0–3. |
LISTENER_WAKE_WORD |
(unset) | listener_loop.py |
Only trigger when the transcript contains this phrase (e.g. hey scout). |
LISTENER_WHISPER_MODEL |
base.en |
listener_loop.py |
faster-whisper model id (base.en). |
ROVER_AEC_DELAY_MS |
150 |
voice_agent.py |
Voice: far-end delay hint for AEC — the rover's speaker→mic round trip (150 ms). |
ROVER_AEC_RATE |
48000 |
voice_agent.py |
Voice (rover audio): pywebrtc echo-canceller sample rate (48 kHz; the model runs at 24 kHz). |
ROVER_GATE_TAIL_S |
0.6 |
voice_agent.py |
Voice: how long the mic stays muted after the model stops speaking (half-duplex gate tail, 0.6 s). |
SCOUT_BRIEFING_DEBOUNCE_S |
4.0 |
voice_agent.py |
Voice bridge: coalesce briefings that arrive within this window into one text turn (4 s). |
SCOUT_BRIEFING_GATE_TIMEOUT_S |
15.0 |
voice_agent.py |
Voice bridge: give up waiting for the in-flight response to end after this many seconds (15 s). |
SCOUT_BRIEFING_MAX_HOLD_S |
20.0 |
voice_agent.py |
Voice bridge: never hold a briefing longer than this while waiting for a quiet moment (20 s). |
SCOUT_BRIEFING_MUTE_SOURCES |
(unset) | voice_agent.py |
Comma list of personas whose briefings are dropped unless URGENT (compose default thinker). |
VOICE_AUDIO |
laptop |
voice_agent.py |
laptop (local mic/speakers) or rover (the rover's mic + speaker over the SDK) — default for --audio. |
VOICE_MODEL |
(unset) | voice_agent.py |
Realtime model id override (e.g. gpt-realtime-2). |
VOICE_NAME |
(unset) | dashboard_server.py, voice_agent.py |
Voice inside the provider (marin, shimmer, matthew, Kore…). |
VOICE_PROVIDER |
openai |
dashboard_server.py, personas.py, voice_agent.py |
openai · nova_sonic · gemini — which bidi speech model the voice persona builds. |
Telegram·
| variable | default | read by | purpose |
|---|---|---|---|
SCOUT_TELEGRAM_ALLOWED_USERS |
(unset) | telegram_listener.py, tools/telegram.py |
Comma list of Telegram user ids allowed to command the rover (empty = anyone — don't). |
SCOUT_TELEGRAM_BOT_TOKEN |
(unset) | telegram_listener.py, tools/telegram.py |
Bot token from @BotFather (preferred name). |
SCOUT_TELEGRAM_DEFAULT_CHAT_ID |
(unset) | tools/telegram.py |
Chat the telegram tool and the thinker post to when none is given. |
SCOUT_TELEGRAM_HISTORY_LIMIT |
(unset) | telegram_listener.py |
How many past messages the Telegram persona keeps in context. |
TELEGRAM_ALLOWED_USERS |
(any) |
telegram_listener.py, tools/telegram.py |
Legacy name for SCOUT_TELEGRAM_ALLOWED_USERS. |
TELEGRAM_BOT_TOKEN |
(unset) | telegram_listener.py, tools/telegram.py |
Legacy name for SCOUT_TELEGRAM_BOT_TOKEN. |
TELEGRAM_DEFAULT_CHAT_ID |
(unset) | thinker_loop.py, tools/telegram.py |
Legacy name for SCOUT_TELEGRAM_DEFAULT_CHAT_ID. |
TELEGRAM_HISTORY_LIMIT |
20 |
telegram_listener.py |
Legacy name for SCOUT_TELEGRAM_HISTORY_LIMIT. |
Thinker·
| variable | default | read by | purpose |
|---|---|---|---|
THINKER_DISABLED |
(unset) | thinker_loop.py |
1 makes the loop a no-op (debugging). |
THINKER_INTERVAL |
60 |
thinker_loop.py |
Seconds between thinker cycles (60). |
THINKER_TELEGRAM_CHAT_ID |
(unset) | thinker_loop.py |
Chat the thinker may post photos/updates to (falls back to the default chat id). |
Personas·
| variable | default | read by | purpose |
|---|---|---|---|
SCOUT_PERSONA |
(unset) | tools/_rover_common.py |
Which persona this process is (thinker, voice, telegram, dashboard…) — the thinker drive gate keys on it. |
SCOUT_PERSONA_FLAGS |
.memory/personas.json |
tools/persona_flags.py |
Path of the shared flags file (.memory/personas.json: thinker_drive, recording). |
SCOUT_REPO |
Path(__file__).resolve().parent.parent |
deploy/scout_supervisor.py |
Supervisor: the compose project directory it runs docker compose in. |
SCOUT_SUPERVISOR_DIR |
REPO / '.supervisor' |
deploy/scout_supervisor.py |
Supervisor: where the socket and audit.log live (default <repo>/.supervisor). |
SCOUT_SUPERVISOR_SOCK |
/run/scout-supervisor/scout-supervisor.sock |
personas.py |
Unix socket where the dashboard reaches the host-side supervisor. |
SCOUT_SUPERVISOR_TOKEN |
(unset) | deploy/scout_supervisor.py, personas.py |
Shared secret both the dashboard and the supervisor read; sent as X-Scout-Supervisor-Token. |
Perception·
| variable | default | read by | purpose |
|---|---|---|---|
COSMOS_BUFFER_CAMERA |
front |
cosmos_buffer.py |
Cosmos ring buffer: front or rear. |
COSMOS_BUFFER_DIR |
cosmos_clips |
cosmos_buffer.py |
Cosmos ring buffer: where finished clips are written. |
COSMOS_CLIP_FPS |
10 |
cosmos_buffer.py |
Cosmos ring buffer: encode fps. |
COSMOS_CLIP_SECONDS |
4 |
cosmos_buffer.py |
Cosmos ring buffer: clip length. |
COSMOS_KEEP_CLIPS |
10 |
cosmos_buffer.py |
Cosmos ring buffer: how many clips to retain. |
DET_BACKEND |
yolo |
yolo_detector.py |
yolo (default) or locate (NVIDIA LocateAnything-3B open-vocabulary grounding). |
LOCATE_ATTN |
sdpa |
yolo_detector.py |
Attention implementation for LocateAnything (sdpa). |
LOCATE_MODEL |
nvidia/LocateAnything-3B |
yolo_detector.py |
HF id for the locate backend. |
LOCATE_QUERY |
person. chair. sofa. table. door. plant. tv. cup. bottle. |
yolo_detector.py |
Natural-language grounding query for the locate backend (person. chair. sofa. …). |
MEDIA_HUB_DATA_INTERVAL |
0.1 |
media_hub.py |
Seconds between /data telemetry pulls. |
MEDIA_HUB_DEFAULT_URL |
http://media:8090 |
media_client.py |
Fallback hub URL when MEDIA_HUB_URL is unset. |
MEDIA_HUB_ENABLED |
auto |
media_client.py |
auto · on · off — whether clients try the hub before polling the SDK directly. |
MEDIA_HUB_MIC_INTERVAL |
0.1 |
media_hub.py |
Seconds between mic buffer drains. |
MEDIA_HUB_MIC_RATE |
16000 |
media_hub.py |
Mic sample rate the hub republishes (16 kHz). |
MEDIA_HUB_PORT |
8090 |
media_hub.py |
MediaHub listen port (8090). |
MEDIA_HUB_REAR |
1 |
media_hub.py |
1 also drains the rear camera stream. |
MEDIA_HUB_URL |
(unset) | media_client.py |
Where clients find the hub (compose: http://media:8090). |
MEDIA_HUB_VIDEO_INTERVAL |
0.1 |
media_hub.py |
Seconds between camera pulls from the SDK (0.1 → ~10 fps). |
SCOUT_ANG_SPEED_MAX |
1.20 |
tools/rover_pose.py |
Dead reckoning: rad/s at angular=1.0 (1.20). |
SCOUT_CAL_FILE |
str(Path(__file__).resolve().parent.parent / '.scout_calibration.json') |
tools/rover_pose.py |
Where speed calibration is persisted. |
SCOUT_ENABLE_COSMOS |
auto |
tools/rover_cosmos.py |
1/0 force the Cosmos tools on/off; auto = present when the package imports (GPU stack). Slim pins 0. |
SCOUT_IMU_YAW_TRUST |
0.15 |
tools/rover_pose.py |
Dead reckoning: complementary-filter weight of IMU yaw (0 = ignore, 1 = trust fully). |
SCOUT_LIN_SPEED_MAX |
0.35 |
tools/rover_pose.py |
Dead reckoning: m/s at linear=1.0 (0.35). |
SCOUT_POSE_DRIFT_BUDGET_M |
8 |
tools/rover_pose.py |
Dead reckoning: pose flagged STALE after this much travel (8 m). |
SCOUT_POSE_FILE |
str(Path(__file__).resolve().parent.parent / '.scout_pose.json') |
tools/rover_pose.py |
Where the estimated pose is persisted between processes. |
SCOUT_POSE_STALE_SECONDS |
1800 |
tools/rover_pose.py |
Dead reckoning: pose flagged STALE after this long (30 min). |
SCOUT_ROOM_SCAN |
str(Path(__file__).resolve().parent.parent / 'cagatay_lab.usdz') |
tools/room_map.py |
Path of the Apple RoomPlan .usdz the room-map tool parses (default cagatay_lab.usdz). |
YOLO_CAMERA |
front |
yolo_detector.py |
front · rear · both. |
YOLO_CONF |
0.35 |
yolo_detector.py |
Detection confidence threshold (0.35). |
YOLO_DEVICE |
auto |
yolo_detector.py |
cuda · cpu · auto. |
YOLO_EVERY_N |
1 |
yolo_detector.py |
Run inference on every Nth hub frame (compose sets 2). |
YOLO_IMGSZ |
640 |
yolo_detector.py |
Inference image size (640). |
YOLO_MODEL |
yolov8n.pt |
yolo_detector.py |
Ultralytics weights (yolov8n.pt, auto-downloaded). |
Datasets·
| variable | default | read by | purpose |
|---|---|---|---|
ECOT_EVENTS_DB |
(unset) | tools/ecot_export.py, tools/reasoning_log.py |
ECoT export: override path of the reasoning events SQLite. |
ROVER_AGENT_ID |
(unset) | tools/_recorder_engine.py |
Persona/agent id folded into the per-day dataset path so several processes append to their own sub-dataset. |
ROVER_AUDIO_RATE |
16000 |
tools/_recorder_engine.py |
Sample rate of the recorded mic track (16 kHz). |
ROVER_BLACK_FRAME_STD |
1.0 |
tools/_recorder_engine.py |
Std-dev threshold under which a frame counts as black. |
ROVER_DATASET_ROOT |
str(ROOT / 'datasets') |
dashboard_replay.py, tools/_recorder_engine.py, tools/ecot_export.py, tools/reasoning_log.py |
Root directory for LeRobot datasets (default datasets/) — recorder and replay API. |
ROVER_MIN_FRAME_DIM |
64 |
tools/_recorder_engine.py |
Reject frames smaller than this many pixels on a side (placeholder images). |
ROVER_RECORDER_DEBUG |
0 |
tools/_recorder_engine.py |
1 prints the macOS SDL2/objc duplicate-dylib warnings instead of spooling them to a file. |
ROVER_RECORDER_LOG |
/tmp/rover_recorder_sdl.log |
tools/_recorder_engine.py |
Where those swallowed SDL warnings go (default /tmp/rover_recorder_sdl.log). |
ROVER_RECORD_ERROR_LOG_PERIOD |
5 |
tools/_recorder_engine.py |
Seconds between repeated 'capture frame error' log lines (anti-spam). |
ROVER_RECORD_FPS |
10 |
tools/_recorder_engine.py, tools/reasoning_log.py |
Dataset frame rate (10 — the earthrover_mini_plus convention). |
ROVER_RECORD_HEIGHT |
480 |
tools/_recorder_engine.py |
Recorded frame height (480). |
ROVER_RECORD_REAR |
1 |
tools/_recorder_engine.py |
1 (default) also records the rear camera as observation.images.rear; 0 = front-only datasets. |
ROVER_RECORD_WIDTH |
640 |
tools/_recorder_engine.py |
Recorded frame width (640). |
ROVER_REJECT_BLACK_FRAMES |
1 |
tools/_recorder_engine.py |
Drop frames whose pixel std-dev is below ROVER_BLACK_FRAME_STD (camera not yet streaming). |
ROVER_REPO_ID |
(unset) | tools/_recorder_engine.py |
Pin one growing LeRobot dataset id; unset = a new scout__earth-rover-mini-YYYYMMDD per day. |
SCOUT_AUTO_RECORD |
1 |
agent.py |
0 disables auto-recording of agent turns. |
SCOUT_AUTO_RECORD_MAX_TASK_LEN |
256 |
agent.py |
Truncate the prompt stored as the episode task to this many chars (256). |
SCOUT_AUTO_RECORD_MIN_ACTIONS |
1 |
agent.py |
Drop auto-recorded episodes with fewer than N motion actions (1). |
SCOUT_CLIP_MODEL |
openai/clip-vit-base-patch32 |
tools/memory_index.py |
Memory index: CLIP model for image embeddings (openai/clip-vit-base-patch32). |
SCOUT_DATASETS_DIR |
datasets |
tools/dataset_index.py |
Dataset index: root to scan for the cockpit/agent list. |
SCOUT_DATASET_MAX_TRACES |
12 |
tools/dataset_index.py |
Dataset index: cap on reasoning-trace paths surfaced. |
SCOUT_DATASET_MAX_VIDEOS |
12 |
tools/dataset_index.py |
Dataset index: cap on video paths surfaced to the agent prompt. |
SCOUT_INJECT_DATASETS |
1 |
tools/dataset_index.py |
1 injects the dataset index into the agent prompt (Cosmos tools need real paths). |
SCOUT_KEYFRAME_MOTION |
1 |
tools/enrich_episode.py |
Episode enrichment: also keyframe when the action changes. |
SCOUT_KEYFRAME_STRIDE |
4 |
tools/enrich_episode.py |
Episode enrichment: keyframe every N frames. |
SCOUT_SEAL_EPISODES |
1 |
tools/_recorder_engine.py |
1 (default) finalizes the dataset after every episode so it is readable mid-session; 0 = packed files, footer only at exit. |
SCOUT_WHISPER_MODEL |
base |
tools/enrich_episode.py |
Episode enrichment: faster-whisper size for transcribing the mic track. |
SCOUT_YOLO_MODEL |
yolov8n.pt |
tools/enrich_episode.py |
Episode enrichment: YOLO weights for offline detection. |
Dashboard·
| variable | default | read by | purpose |
|---|---|---|---|
CAROOT |
(unset) | tls.py |
mkcert CA root directory (mkcert's own variable), honoured when exporting /ca. |
DASH_HOST |
0.0.0.0 |
dashboard_server.py |
Bind address of the cockpit server. |
DASH_PORT |
8080 |
dashboard_server.py, field_setup.py, scout_mdns.py, tls.py |
Cockpit port (8080). |
DASH_TLS |
true |
dashboard_server.py, field_setup.py, tls.py |
true serves HTTPS with a generated self-signed cert (WebAuthn needs it). |
DASH_TLS_CERT |
(unset) | tls.py |
Use this real certificate instead of generating one. |
DASH_TLS_DIR |
./.scout_tls |
dashboard_server.py, field_setup.py, tls.py |
Where the generated cert/key are kept (compose: the auth volume). |
DASH_TLS_HOSTS |
(unset) | tls.py |
Extra SANs to put in the generated cert (a private domain, scout.local). |
DASH_TLS_KEY |
(unset) | tls.py |
Private key matching DASH_TLS_CERT. |
DASH_TLS_MKCERT |
auto |
dashboard_server.py, tls.py |
auto uses mkcert when installed for a locally-trusted cert. |
DASH_TURN_SIGN |
-1 |
dashboard_server.py |
Flip the joystick/WASD angular sign (default -1), independent from ROVER_TURN_SIGN. |
SCOUT_MDNS_NAME |
scout |
field_setup.py, scout_mdns.py, tls.py |
mDNS name announced on the LAN (scout → scout.local). |
SCOUT_PUBLIC_URL |
(unset) | dashboard_server.py |
Public URL printed on the field card / QR and used for links (else the request Host). |
Auth·
| variable | default | read by | purpose |
|---|---|---|---|
SCOUT_AUTH_BOOTSTRAP_TOKEN |
(unset) | auth.py, dashboard_server.py, field_setup.py |
One-time secret required to enrol the FIRST passkey — set it before exposing a fresh rover to the internet. |
SCOUT_AUTH_ORIGIN |
(unset) | auth.py |
Expected WebAuthn origin (derived from the request when unset). |
SCOUT_AUTH_RP_ID |
(unset) | auth.py |
WebAuthn relying-party id — the public hostname when behind a tunnel. |
SCOUT_AUTH_RP_NAME |
scout rover |
auth.py |
Display name shown in the passkey prompt. |
SCOUT_AUTH_STORE |
./.scout_auth.json |
auth.py |
Path of the passkey + JWT-secret store (auth.json, chmod 600). |
SCOUT_AUTH_TOKEN_TTL |
86400 |
auth.py |
Session JWT lifetime in seconds (24 h). |
Fleet·
| variable | default | read by | purpose |
|---|---|---|---|
TINY_MCP |
0 |
tools/tiny_mcp.py |
1 mounts the tiny.technology fleet tools into the agents (off by default). |
TINY_MCP_COMMAND |
(unset) | tools/tiny_mcp.py |
Full command to start the MCP server (overrides node/tiny-tech autodetection). |
TINY_MCP_HOME |
~/.tiny-mcp |
tools/tiny_mcp.py |
Isolated TINY_HOME for the server (default ~/.tiny-mcp). |
TINY_MCP_MESH |
0 |
tools/tiny_mcp.py |
1 lets the server join the zenoh mesh (off: CPU). |
TINY_MCP_NODE |
(unset) | tools/tiny_mcp.py |
Path to the node binary. |
TINY_MCP_PERSONAS |
(unset) | tools/tiny_mcp.py |
Comma list of personas that get fleet tools (default dashboard, telegram, shell). |
TINY_MCP_STARTUP_TIMEOUT |
45 |
tools/tiny_mcp.py |
Seconds to wait for the MCP server to come up (45). |
TINY_MCP_TIMEOUT |
90 |
tools/tiny_mcp.py |
Per-tool-call read timeout in seconds (90). |
TINY_MCP_TINY_TECH |
(unset) | tools/tiny_mcp.py |
Path to the tiny-tech package dir (image: /opt/tiny-mcp/node_modules/tiny-tech). |
TINY_SELF_DEVICE_IDS |
(unset) | tools/tiny_mcp.py |
This robot's own device ids/names — use_device refuses to invoke them. |
TINY_SELF_NAME |
(unset) | tools/tiny_mcp.py |
Name stamped into the [fleet depth=1 from <name>] marker on outgoing fleet turns. |
TINY_TOKEN |
(unset) | tools/tiny_mcp.py |
tiny.technology user CLI JWT the MCP server authenticates with (lives in .tiny-mcp.env). |
TINY_TOKEN_FILE |
(unset) | tools/tiny_mcp.py |
Read the token from a file instead (wins over TINY_TOKEN). |
Scout·
| variable | default | read by | purpose |
|---|---|---|---|
SCOUT_MEMORY_DIR |
.scout_memory |
memory.py, tools/rover_memory.py |
Directory of the shared SQLite brain (.scout_memory locally, .memory in compose). |
SCOUT_MEMORY_PROMPT_MAX |
1000 |
memory.py |
Max chars of recalled memory injected into the system prompt. |
SCOUT_MEMORY_RECALL_TURNS |
8 |
memory.py |
How many recent turns to recall. |
SCOUT_MEMORY_REPLY_MAX |
1500 |
memory.py |
Max chars of a reply stored per turn. |
Other·
| variable | default | read by | purpose |
|---|---|---|---|
STRANDS_MODEL_ID |
(unset) | dashboard_server.py |
Bedrock model id for every text persona; editable live from the cockpit ⚙️ drawer. |
155 variables, scanned from every os.getenv / os.environ in the repo.