# Makepad Builder This is the generic app builder/compiler. Scope is catalog data, not a separate installer. Keep the legacy CLI compatible. ## Architecture and validation - Platform dependency installation, network requests, extraction and source checkout belong on the persistent setup worker. The UI only submits bounded commands and receives progress/results. - The Windows ZIP is flat and ships one executable, `makepad-builder.exe`. It hosts `MpTerm` and launches itself in `tui` mode for setup; the internal native CLI target is for development/SDK extraction, not distribution. Start the PTY at the measured widget/font grid size. The setup process owns blocking work, and child shells/agents inherit its ConPTY instead of opening another window. macOS/Linux use the invoking terminal. The TUI follows `makepad-windows-preview.sh` (Windows) and `makepad-mac.sh`: plain terminal colours (dim secondary text, bold selection, green ✓, yellow pending, cyan marker and bar; no panels or boxed dialogs), a header with the email, SETUP in the order people meet them (Account, Graphics, Agreements, Build tools or Rust + Xcode tools/System packages, optional CUDA, Disk, Update), YOUR APPS, MAKEPAD APPS and CODING AGENTS rows with name, license and status columns and the action hint ` ⏎` on the selected row only, one status line and a key-hint footer. App states and actions come from `menu.txt` (download / resume / compile / update / run / merge with agent); the subtitle is `about.txt`. Questions sit on the status line with their options on the next line; progress is one self-rewriting bar there, with detail in `builder.log`. App agents require both compiler and source. Do not show a Project shortcut or a second top menu bar. - Dependency setup progress comes from real installer events. Each component (Build tools, Windows SDK, Rust, CUDA) has one forward-only bar over the byte sizes of all its payloads, known before it starts (manifest sizes, cached files, Content-Length), each counted once downloaded and once unpacked; a line above lists the components that run (✓ done, ● now, ○ next). Never list package or file names on screen; they go to `builder.log`. Keep terminal redraws throttled; never invent an overall byte percentage from package counts. The same events serve the Windows terminal host and SDK extraction CLI. - Run installed agents only after an explicit menu action. Keep compiler output in the log and suppress new Windows consoles for setup/build probes and application launch: children inherit the setup process's pseudo console when it has one and only a console-less parent requests a hidden console. Do not install agents or runtimes implicitly. Preserve the user's PATH after the selected compiler paths so installed tools remain reachable. Project children inherit the selected project directory and no email credential. - GPU driver notice: Linux and Windows setup show the Graphics screen ("Makepad heavily relies on your GPU to draw its UI and implement AI functionality. Old hardware and broken drivers can cause your computer to reboot unexpectedly.", `I understand` selected, Cancel) before any probe, catalog refresh, download or compile until it is read; Cancel/Escape/closed input quit setup. "I understand" is recorded in the install folder (`graphics-notice-read`, temp+rename) and the notice is not shown on later starts; the SETUP Graphics row then shows "✓ driver notice read" and reopens the screen, where Cancel does not un-read it. macOS does not show it. It is a general acknowledgement, separate from vendor license consent (`Setup::consent`). On Windows the terminal host already renders with the GPU before the menu appears; the notice precedes payload downloads and installs, not GPU use itself. - Compiler policy is platform specific. Windows always downloads and uses the Builder-private pinned Rust; it never offers, reads or uses an installed rustc/cargo or the `selected-rust` file. macOS/Linux may reuse the user's installed Rust only when the user explicitly chooses it and it meets the pinned version on this host; the choice (sysroot or `private`) is recorded in `selected-rust`, re-validated on every start and before every build, and never auto-switched. Cargo home, target and temp directories stay in the installation either way. `rust-tools.sh` is the single read-only probe/validator shared by the bootstrap and Builder; it runs the toolchain's own binaries, never installs, and never repairs an external toolchain. - Downloaded Windows ZIPs are portable: keep Rust, Cargo home, sources and build output beside `makepad-builder.json` in the extracted folder. Unpersonalized development/legacy runs fall back to `~/.makepad/loader`; explicit root overrides remain supported. Do not modify global compiler PATH, rustup defaults or system compiler installations. The Builder never edits the user PATH or shell profiles. The terminal and CLI must use the same `runtime::Environment`. - Publish the compiled Windows app beside the loader (for Scope, `scope.exe`). Unix keeps its shell command beside `scope.bin`. Compile with `MAKEPAD_PACKAGE_DIR=.` and write per-executable `makepad-package-paths` from the successful build's Cargo compiler artifacts. Map actual library/binary crate names to source directories relative to the executable; all fonts/icons/crate resources remain in the downloaded repositories. Recompute tool paths on each launch; validate after physically moving the installation and launching from an unrelated directory. - App agents start in the app Cargo workspace with the private build environment and session-only instructions pointing to `agent-context.txt`. The CODING AGENTS Shell row also receives `MAKEPAD_AGENT_CONTEXT`; the Claude/Codex rows inject the startup instruction automatically (Grok reads the context file); rows appear only for agents found on PATH. Shells and agents use the current CUDA selection and clear inherited Rust compiler wrappers/encoded flags. Preserve repository instructions and user authentication/permissions. Never install an agent implicitly or expose the bootstrap credential. `makepad-builder.exe rebuild` / `makepad-builder rebuild` rebuild existing edited sources and refresh the root executable/resource map without fetching a release. - Compiler setup has one consent screen ("› Install build tools": what is installed in this folder, each agreement by name and host with Return opening it in the browser, then "Agree to all" selected and Cancel) covering all required terms (Makepad commercial license, Microsoft tools/SDK and private Rust on Windows); never prompt again between those components. The Agreements screen shows each agreement's state and offers Agree to all / Disagree; `agreements-accepted` records it, consent screens skip what is already accepted, and disagreeing only withdraws the record (nothing installed is removed). The Build tools row is ✓ only when both tools and the selected Rust (private pinned, or the recorded installed Rust on macOS/Linux) are ready. The CUDA compiler is optional on x64 Windows, including releases that do not require it by default. Offer it only with an NVIDIA driver present, behind its own consent screen (NVIDIA CUDA Toolkit); enabled builds use the private toolkit and require CUDA kernels when the app includes that backend. macOS developer tools are checked, not silently installed or licensed. On macOS the "› Apple developer tools" screen offers Apple's installer (`xcode-select --install`, then polls) or runs `sudo xcodebuild -license` on the real terminal, plus Check again and Cancel; it follows the agreements on first run and compiling requires it. Unix dependency readiness uses the same `check-tools.sh` in the bootstrap and Rust frontend. If setup is needed, pause the TUI for Apple or the distro package-manager interaction, then resume it. Never interpret Linux as Apple-ready. macOS uses Metal; the Windows CUDA option is not shown. - Email is the only customer identity and access credential. Downloads are not personalized: `makepad.nl/builder/{macos,linux,windows}` serve the same bootstrap to everyone; the TUI opens with a "› Log in" screen once per folder (empty continues with the open source experiments), saves the email in the folder's `makepad-builder.json` and never asks again; without an email only public experiments show and the menu offers "log in". The user explicitly requested personalized URLs: `/{app}/windows?email=...`, `/{app}/mac?email=...`, `/{app}/linux?email=...`, and `/{app}/git?email=...`. Percent-encode values and never follow credentialed redirects. Keep email out of Git remotes, build environments, logs and source releases. The downloaded bootstrap stores app/email; CLI and environment overrides remain supported. Catalog and legacy API authentication still use `X-Makepad-Email`. This deliberately does not verify ownership of the email address. - Check/build from the main workspace with `cargo check -p makepad-loader`, `cargo build --release -p makepad-loader`, and existing `cargo test --release -p makepad-loader -p makepad-git -p makepad-strict-json`. Verify Windows and native macOS UI using owned standalone `--remote` instances. Do not treat a successful compiler build as proof of the installation flow. ## Shared apps - Makepad experiments (the free apps) is one scrolling list, with selection retained when returning from an app. Keep the selected row visible after keyboard/wheel input and terminal resizes; do not split the list into numbered pages. - Builder opens the downloaded Makepad repository by default. Only an explicit `MAKEPAD_LOADER_PROJECT` overrides that; installer scripts must not set it to the invoking shell's directory. The standalone `scope` command still opens the invoking directory. - `apps.json` lists the public Cargo workspace apps and their binary/required features, with explicit menu placement for the curated list; the shared TUI uses it. Scope alone requires an enabled email. The public catalog projects only the verified public Makepad repository from the matching release and never exposes the Scope pack. - Licensed apps (Scope first) are rows under YOUR APPS. Makepad experiments lists Makepad WM and the registry entries marked `menu: other`; choosing any of them immediately sets up any missing compiler, builds and launches that app, then returns to Builder with the list's selection kept. No app opens a nested checklist. Launching an app uses cached release metadata (a built app just runs), projecting only its public Makepad repository; check for newer sources only through setup/update actions. The active app is recorded in `selected-app` for rebuilds and restored to Scope on return. Sources share `sources//makepad`; verified per-repository receipts allow adding the nested Scope checkout without resetting edited Makepad sources. Stage missing repositories individually and leave unverified existing directories untouched. - Use one `target/` and one selected compiler environment across apps and agents. Shared artifacts need shared source paths: a release builds from its own `sources/` when that exists, otherwise from an existing snapshot whose receipts pin the same commits (receipts match on the commit, not the pack hash), so a public app at the installed Scope's Makepad commit builds from Scope's checkout; only a differing Makepad commit creates a new snapshot, and the activity log says which case applies before anything downloads. Builds and agent shells strip inherited Cargo profile/target/rustflags overrides and pin `RUSTFLAGS`. Installed app metadata lives in `installed/.json`. Publish each executable with its own adjacent `.makepad-package-paths`, retaining the shared map for older runtimes. This keeps previously built apps bound to their matching source resources. - GUI launches return immediately to Builder. Poll child exits without blocking the menu; shell/agent sessions still return when their interactive session ends. On macOS publish a stable `.app` beside the root command/binary, with a real executable, Dock icon and relative resource link. Dock launches reopen the saved project; the terminal command opens its invoking directory. Keep project state outside the app bundle and preserve relocation of the complete installation folder. - Opening Builder starts compiler setup, source download, compilation and Scope launch automatically on every platform. Resolve one release for the sequence and reuse ready dependencies. Required license/install confirmations remain interactive; cancellation and failures return to the menu without advancing or retrying automatically. Updates refreshes licenses and pulls clean sources for installed apps with a newer release; edits in the old snapshot are first saved as `changes/-.diff` and `.files`, the app then offers "merge with agent". Disk shows the folder total and the build data; "clean build" deletes `target/` only, never the apps. Returning from Makepad Apps or a launched app must not restart the startup sequence. - On macOS Builder explicitly opts Scope into foreground activation with the `--focus` argument. Preserve the default activation policy of other apps and remote inspection windows. ## Building the Windows download on Linux - Build the native CLI without UI dependencies using `cargo build --release -p makepad-loader --no-default-features --bin makepad-builder-cli`. - After explicit installation/license approval, `makepad-builder-cli windows-sdk --root DIR --accept-ms-license` downloads Visual Studio 2022 payloads from Microsoft and uses the same Rust VSIX/MSI/CAB extraction as Windows setup. Never copy SDKs from a developer's Windows machine. No Wine, Windows installer execution or registry changes are required. - `cross-windows.py --sdk-root DIR` uses the already installed Windows Rust target, Rust's bundled LLD, and extracted import libraries. It checks/builds the terminal host and CLI with static CRT and packages `windows-x86_64.zip`, plus a build record. It does not install missing software. Runtime-check the ZIP on Windows before publication; compiler success alone is not runtime proof. ## Commercial release service Default endpoint: `https://makepad.nl/api/loader`. The server lives in the makepad/webserver repository. - `GET /catalog`: permitted releases, no quota charge. - `POST /source/{app}/{release}/{repository}.pack`: one self-contained Git pack for the pinned commit. Charge one repository-transfer attempt before streaming; failed/interrupted transfers count. No redirects or query parameters. - `GET /{app}/git?email=...`: latest app repository pack; optional `release` and `repository` pin a catalog entry. Source transfers use the same atomic quota; HEAD and installer downloads do not consume repository quota. - Windows downloads stream a common ZIP plus a small personalized bootstrap suffix using `libs/loader_bundle`. No per-email ZIP is written to server disk. `MAKEPAD_LOADER_RUNNERS` selects the artifact directory, containing `windows-x86_64.zip`. - macOS and Linux downloads are POSIX shell bootstraps with a shared terminal menu, not precompiled runners. `installer.sh`, `bootstrap.sh`, `rust-tools.sh` and `check-tools.sh` form the complete auditable POSIX script. Detect architecture automatically. Prompt for a folder; keep Cargo home, sources and one shared target directory there. Check system tools, then offer a compatible installed Rust once (recording the answer in `selected-rust`) or download pinned private Rust, fetch one public Makepad commit from the immutable verified pack, and compile `makepad-builder-cli --no-default-features` into `makepad-builder` beside `run-builder.sh`. `run-builder.sh` always re-enters the bootstrap, whose fast path validates the recorded choice and opens the menu directly when nothing needs attention. No Python or prebuilt Unix Builder is required. Verify Rust archives with their vendor SHA-256 metadata and verify the pinned Git tree before writing its reuse receipt. Platform curl performs TLS downloads without redirects or credentials in process arguments. - `launcher.sh` becomes the app command in that folder. Resolve symlinks without changing the caller's directory; `scope` opens that directory and `scope /path` opens the explicit project. Keep installed paths relative for portable folders. Offer `~/.local/bin` and shell PATH configuration only with explicit acceptance; never expose private Rust globally. - macOS checks the selected developer tools (honoring DEVELOPER_DIR), the actual compiler, macOS SDK, linker and Git. Do not gate on Xcode's broader first-launch status: working command-line tools are sufficient. Preserve tool diagnostics, including actual Apple license failures, and guide missing setup through Apple's installer or an interactive license prompt; never automatically accept a license or change the global active developer directory. - Linux distro package choices cover Debian/Ubuntu, Fedora/RHEL, Arch and openSUSE. Ask before installing packages or private Rust. Support glibc x86_64/ARM64 when advertised by the release; stop for unsupported libc/architecture and offer manual dependency setup for other distros. - Verify advertised size, SHA-256 and Git objects before committing a staged release directory. Existing installed releases remain available if an update fails. - The authenticated catalog pins Rust version, supported platforms, workspace, Cargo package and executable, CUDA support, repository paths, commits, byte counts and SHA-256 hashes. Use the built `makepad-builder-cli publish` command to produce packs and manifests. Required arguments: `--app-id`, `--title`, `--package`, `--binary`, `--release`, `--makepad`, `--app-repo`, `--out`. `--rust` pins the compiler, `--cuda` advertises optional CUDA. Normal publication uses each repository's HEAD; `--snapshot` explicitly packages tracked working changes and new Rust/Cargo files under app src/deps using a temporary Git index. It does not modify the real index or branches. Verify inclusion before publishing. Release IDs are immutable. Publish the matching Makepad/app revision pair; never accidentally package an unrelated or archived checkout. Private service data must stay outside the public document root. `licenses.sqlite3` uses `makepad-sqlite` and contains email addresses, app entitlements, enabled flags, download limits and aggregate download counters. There are no separate license keys, names, IP records, timestamps or download-history records. Do not add request logging for downloads. Counter reservation is transactional and happens before streaming; updates to access and limits preserve the count. Keep the database across deploys. The persistent service worker owns its connection and performs source preparation; connection threads stream completed pack files. `apps/{id}/source.json` configures the matching Makepad and app repository URLs/branches plus catalog fields. The service fetches shallow Git history using its read-only GitHub deploy key, packs the pinned trees into immutable `releases/{id}/{release}/*.pack`, and atomically updates `apps/{id}/latest.json`. Git caches live under `git-cache/`. GitHub host keys are pinned in `github-known-hosts`; the private deploy key defaults to `deploy_key`, with `MAKEPAD_LOADER_DEPLOY_KEY` as an override. Never copy the VPS deploy key off that server. Catalog checks refresh at most once per 30 seconds; the admin refresh button forces a refresh. The HTML console at `/admin` (also `/admin/loader`) manages emails, app access and limits and shows aggregate counts. `admin_ip` holds the one permitted public IP. Trust forwarded client IPs only from verified Cloudflare peers; enforce the expected Host, same-origin JSON requests and the admin request header. Missing IP configuration denies access. The console has no third-party scripts or assets. CLI maintenance uses `makepad-web-server --loader-admin init|users|user-set|user-remove|refresh|track --data `; user commands accept `--email`, `--apps` and `--limit` as applicable. `track --app --repository --branch ` (also `POST /api/loader-admin/track`) changes only that already configured repository's branch and drops a temporary `pinned_release`; it fetches and packs the candidate pair first and activates configuration then `latest.json`, keeping the previous pair on failure. `pin` exists only to keep downloads alive while a branch is retired. The server defaults to `/loader`; `MAKEPAD_LOADER_DATA` overrides this. The service account owns this private directory, including the database, source cache and release outputs. Return private/no-store, CDN-Cache-Control and Cloudflare-CDN-Cache-Control headers. Cloudflare rules must not override these; verify the actual public endpoint during deployment. Stage, test and retain a rollback binary before restarting the existing website service. Preserve its current service flags and map data.