Environment variables: toolchain & SDK discovery

Day locates host toolchains and SDKs through one shared implementation (crates/day-toolchain), used by the day CLI, by every crate build script that compiles its own native shim (day-xaml-sys, the day-piece-*/day-tweak-* crates, and the scaffolds day new generates). Two rules apply everywhere:

  1. An environment variable always wins over probing.
  2. Defaults derive from the platform’s environment (%ProgramFiles%, $HOME, %LOCALAPPDATA%), never from a literal install path, so a relocated install needs only one variable set.

Build scripts emit cargo:rerun-if-env-changed= for their overrides, so changing one re-runs the affected script instead of keeping stale results.

Windows

VariableMeaningFallback when unset
DAY_CPPWINRTExact C++/WinRT header dir (…\Include\<ver>\cppwinrt). An override that fails validation (winrt/base.h missing) is an error, not silently ignored.scan below
DAY_WINDOWS_KITS_ROOTThe …\Windows Kits\10 root (headers and bin tools resolve under it)WindowsSdkDir, then %ProgramFiles(x86)%/%ProgramFiles% + Windows Kits\10
WindowsSdkDirMS-standard (set by Visual Studio developer shells); honored after the DAY_ vars
DAY_WINDOWS_KITA bin directory containing signtool.exe/makeappx.exe directly (day pack tool lookup)PATH, then bin\<ver>\<arch> under the kits roots
DAY_MAKENSISThe makensis executable for NSIS installersPATH, then %ProgramFiles(x86)%/%ProgramFiles% + NSIS, then chocolatey (%ChocolateyInstall%\bin shim, else …\lib\nsis\tools\<ver>)

Android / JDK

VariableMeaningFallback when unset
ANDROID_HOME / ANDROID_SDK_ROOTAndroid SDK root (standard)~/Library/Android/sdk (macOS), %LOCALAPPDATA%\Android\Sdk (Windows), ~/Android/Sdk (Linux)
ANDROID_NDK_HOMENDK rootnewest NDK under <sdk>/ndk
JAVA_HOMEJDK for Gradle (AGP 9 needs 17+; Gradle 9.7 runs on 17…26)macOS: /usr/libexec/java_home -v 17+, then a Homebrew openjdk keg (either prefix)
DAY_ANDROID_ABIForce the cargo-ndk ABI list for the build (comma/space-separated); takes precedence over any connected device (CI walkthrough: x86_64; dual-ABI pack: arm64-v8a,x86_64; each ABI needs its rustup target)connected devices’ ABIs, else arm64-v8a

OpenHarmony

VariableMeaning
OHOS_NDK_HOMEThe SDK’s native dir (cross-linker + shim compiles); set by CI’s setup-ohos-sdk
OHOS_BASE_SDK_HOME / OHOS_SDK_HOMESDK root(s); also probed for hap-sign-tool.jar
DAY_OHOS_ARCHForce the build arch (device / arm64 / x86_64). Takes precedence over any connected device, so a day pack produces the same hap whether or not an emulator is running; leave it unset to build for each attached target

Rust toolchain

VariableMeaningFallback when unset
RUSTUP_HOMErustup root for cross-std toolchains (mobile targets need rustup’s per-target std; a Homebrew/system rustc has none)~/.rustup; among installed toolchains a stable-* one is preferred

Linux packaging

VariableMeaning
DAY_GNOME_RUNTIME / DAY_KDE_RUNTIMEPin the flatpak runtime branch day pack targets (GTK ⇒ org.gnome.Platform, Qt ⇒ org.kde.Platform)
DAY_LINUXDEPLOYThe linuxdeploy executable that builds the .appimage. Checked before PATH, because linuxdeploy ships as a downloaded AppImage rather than a package
DAY_LINUXDEPLOY_PLUGIN_GTK / DAY_LINUXDEPLOY_PLUGIN_QTSame, for the toolkit plugin. Absent, day pack still builds an AppImage and warns that it carries no GTK/Qt modules

Scaffolding & signing

VariableMeaning
DAY_LOCALMake day new scaffolds depend on a local day checkout instead of the git remote (CI)
DAY_THEMElight | dark — forces the app’s theme on every backend (AppKit appearance, libadwaita color scheme, Qt 6.8+ color scheme, UIKit interface style, Android night mode, XAML element theme, OHOS color mode); unset = follow the system. CI’s themed screenshot cycles pass it via day launch --env. An app that applies its own persisted appearance at startup must honor the env-wins rule (docs/prefs.md): skip the boot application when DAY_THEME is set, or the app clears the forced theme right back; day-piece-settings::apply_startup does this for you, and Day Showcase’s hand-rolled menu plumbing shows the guard (src/commands.rs)
DAY_WINDOW<width>x<height> (e.g. 700x850) — overrides the app’s initial window size for responsive-layout testing on desktop backends; mobile/web size to the screen and ignore it
DAY_CAPTURE_SIZE<width>x<height>[@<scale>] in pixels, or window — read by day launch --script: what the run captures desktop-class targets at, over Day.toml [screenshots] and under --capture-size (website docs “dayscript”, “Capture size”)
DAY_CAPTURE_SCALEthe scale a window snapshot is rendered at (2) — set by day launch --script from the capture size; honored by the backends that render their own snapshot (GTK, Qt), and on GTK and XAML it also marks the window size as the size of the CAPTURE rather than of the window around it
DAY_CAPTURE_DISPLAYnative or virtual — read by day launch --script on macOS: never, or always, create the HiDPI virtual display a macos-appkit capture uses when no attached display has the capture’s scale. Unset decides by the displays attached
DAY_WINDOW_SCREENa CGDirectDisplayID — macos-appkit opens its window on that display; set by day launch --script to the capture display it created
DAY_WEB_DRIVER_VIEWPORT<width>x<height>[@<scale>] in points — the bundled web driver’s viewport and device scale factor; set by day launch --script from the capture size, default 1280x800@2
DAY_APP_VERSION, DAY_SCRIPTThe app’s version and the driving script’s file name, set by day launch on every run. A debug build appends them to every window title as (version/toolkit[/script])docs/windows.md. Release builds ignore both
ANDROID_SERIALadb’s standard device nav host; when set, day build/launch and dayscript sessions target only that device instead of every connected one
DAY_LOG_ACTIONS1 narrates every user action to stdout in the dayscript vocabulary (dayscript ▸ tap inc "Add") without recording anything, the same lines a recording echoes (§14.6). An app can also call day::record::log_actions(true); Day-Showcase does, and reads DAY_LOG_ACTIONS=0 as the way to silence it
DAY_VERBOSE1 | true — the global --verbose flag, from the environment: every day command forwards its sub-commands’ raw output (cargo, gradle, xcodebuild, hvigor, adb, codesign, …) instead of capturing it. One env: line turns a whole CI job verbose, including invocations no flag can reach (the launches a generated dayscript runner performs). An explicit --verbose on the command line also turns it on; any other value (or unset) leaves the default quiet output
DAY_SCRIPT_MAIN_TIMEOUT_SECSHow long one dayscript step waits for the app’s main thread before failing (default 30). This is not the step’s implicit-wait budget; it covers a main thread that has not answered at all, which is a property of the machine (a shared CI vCPU compositing its first frame) rather than of the script. Raise it on a slow runner
DAY_SIGN_STORE_PASS, DAY_SIGN_KEY_PASSThe keystore and key passwords day sign apply --keystore signs with. They live here rather than in the argument list, which every other process on the machine can read, and they are what lets a distributor sign a package without the project that built it (docs/packaging.md)
DAY_FLAVORThe build flavor to apply, the global --flavor flag from the environment: day build, every scripted launch and day pack read Day-<name>.toml as a layer over Day.toml (docs/flavors.md). One env: line builds a whole CI matrix leg as the flavor, and the value crosses into the xcodebuild and gradle callbacks so the identity they write is the flavor’s
DAY_RESOURCE_ROOTThe resource tree day-build reads in the app’s build.rs, in place of <project>/resource. Set by day build --flavor to the merge of the app’s tree and the flavor’s overlay, under build/day/flavors/<name>/resource; unset for a plain build
DAY_SELF_COMMANDHow day mcp-server re-invokes the CLI for each tool call, as a JSON array of argv[0] plus any leading arguments (["cargo","run","--manifest-path","…/Cargo.toml","-q","-p","day-cli","--"]). Unset, a tool call runs the server’s own executable. The VS Code extension sets it when day.cliSource points at a day checkout, so an edit to day-cli reaches the agent’s tools the same way it already reaches the editor’s Build and Run — see docs/agent.md. An unusable value falls back to the default rather than failing every tool
DAY_SIGN_*, DAY_NOTARY_*, DAY_ASC_*, DAY_KS_PASS, …Release-signing secrets referenced from Day.toml’s [signing] tables via ${VAR}; resolved at pack time, degrade to the dev signing tier when unset (§20)

Signing variables are listed exhaustively by day sign check, which reports each platform’s readiness without printing a secret value.

Network

Day makes exactly two kinds of outbound call, both disableable:

VariableMeaning
DAY_NO_UPDATE_CHECKSet to any non-empty value to disable the background “a newer day-cli is on crates.io?” check, the only outbound call day makes, so setting it keeps day fully offline.