# Default recipe (runs when just is called without arguments) default: @just --list # Read nightly toolchain from rust-toolchain.toml (single source of truth). nightly_toolchain := `grep '^channel' rust-toolchain.toml | sed 's/.*"\(.*\)"/\1/'` # Format Rust code format: cargo +{{nightly_toolchain}} fmt --all # Check if code is formatted format-check: cargo +{{nightly_toolchain}} fmt --all -- --check # Run the full live provider integration workflow locally (sources .envrc when present). provider-e2e-weekly: ./scripts/run-provider-integration-weekly.sh # Run only the scenario-driven provider E2E serialization checks. provider-e2e-scenarios: ./scripts/run-provider-e2e-daily.sh # Compatibility alias for the old daily recipe name. provider-e2e-daily: provider-e2e-scenarios # Verify Cargo.lock is in sync with workspace manifests. lockfile-check: cargo fetch --locked # Lint Rust code using clippy (OS-aware: macOS excludes CUDA features) lint: lockfile-check #!/usr/bin/env bash set -euo pipefail if [ "$(uname -s)" = "Darwin" ]; then cargo +{{nightly_toolchain}} clippy -Z unstable-options --workspace --all-targets --exclude moltis-providers --exclude moltis-gateway --exclude moltis-matrix --timings -- -D warnings cargo +{{nightly_toolchain}} clippy -Z unstable-options -p moltis-providers --all-targets --features local-llm-metal --timings -- -D warnings cargo +{{nightly_toolchain}} clippy -Z unstable-options -p moltis-gateway --all-targets --features local-llm-metal --timings -- -D warnings else cargo +{{nightly_toolchain}} clippy -Z unstable-options --workspace --all-features --all-targets --timings -- -D warnings fi # Build Tailwind CSS for the web UI. build-css: cd crates/web/ui && ./build.sh # Build Vite frontend JS (TS/TSX -> dist/). build-frontend: cd crates/web/ui && npm run build # Build the service worker (sw.ts -> sw.js). build-sw: cd crates/web/ui && npm run build:sw # Build all web assets (Vite JS + Tailwind CSS + service worker). build-web-assets: ./scripts/build-web-assets.sh # Ad-hoc codesign debug binaries (macOS only, requires MACOS_CODESIGN_IDENTITY). # Signs the main binary and all test binaries in target/debug/deps/ so Little # Snitch doesn't prompt on every rebuild during local dev. [private] codesign-debug: #!/usr/bin/env bash [ "$(uname -s)" = "Darwin" ] || exit 0 [ -n "${MACOS_CODESIGN_IDENTITY:-}" ] || exit 0 id="${MACOS_CODESIGN_IDENTIFIER:-org.moltis.dev}" sign() { codesign --force --sign "$MACOS_CODESIGN_IDENTITY" --identifier "$id" "$1" 2>/dev/null || true; } # Main binary if [ -f target/debug/moltis ]; then sign target/debug/moltis; fi # Test binaries (Mach-O executables, skip .d/.fingerprint/dylib) for bin in target/debug/deps/moltis*; do if [ -f "$bin" ] && [ -x "$bin" ] && [[ "$bin" != *.d ]]; then sign "$bin"; fi done # Build the project build: build-web-assets cargo build just codesign-debug # Build in release mode build-release: ./scripts/cargo-build-moltis.sh --release # Build embedded WASM guest tools and pre-compile to .cwasm for AOT loading. wasm-tools: cargo build --target wasm32-wasip2 -p moltis-wasm-calc -p moltis-wasm-web-fetch -p moltis-wasm-web-search --release cargo run -p moltis-wasm-precompile --release # Build just the release WASM artifacts expected by embedded-wasm builds. build-wasm-artifacts: wasm-tools @echo "Built target/wasm32-wasip2/release/{moltis_wasm_calc,moltis_wasm_web_fetch,moltis_wasm_web_search}.{wasm,cwasm}" # Build release after ensuring embedded WASM artifacts are present. build-release-with-wasm: build-wasm-artifacts ./scripts/cargo-build-moltis.sh --release # Run local dev server with workspace-local config/data dirs. dev-server: cargo build --bin moltis just codesign-debug MOLTIS_SLACK_API_BASE_URL_ALLOWLIST=localhost,127.0.0.1 MOLTIS_CONFIG_DIR=.moltis/config MOLTIS_DATA_DIR=.moltis/ cargo run --bin moltis # Build Debian package for the current architecture deb: build-release build-wasm-artifacts bash ./scripts/stage-wasm-package-assets.sh target/release cargo deb -p moltis --no-build # Build Debian package for amd64 deb-amd64: build-wasm-artifacts ./scripts/cargo-build-moltis.sh --release --target x86_64-unknown-linux-gnu bash ./scripts/stage-wasm-package-assets.sh target/x86_64-unknown-linux-gnu/release cargo deb -p moltis --no-build --target x86_64-unknown-linux-gnu # Build Debian package for arm64 deb-arm64: build-wasm-artifacts ./scripts/cargo-build-moltis.sh --release --target aarch64-unknown-linux-gnu bash ./scripts/stage-wasm-package-assets.sh target/aarch64-unknown-linux-gnu/release cargo deb -p moltis --no-build --target aarch64-unknown-linux-gnu # Build Debian packages for all architectures deb-all: deb-amd64 deb-arm64 # Build Arch package for the current architecture arch-pkg: build-release #!/usr/bin/env bash set -euo pipefail VERSION="${MOLTIS_VERSION:-$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')}" ARCH=$(uname -m) PKG_DIR="target/arch-pkg" rm -rf "$PKG_DIR" mkdir -p "$PKG_DIR/usr/bin" cp target/release/moltis "$PKG_DIR/usr/bin/moltis" chmod 755 "$PKG_DIR/usr/bin/moltis" cat > "$PKG_DIR/.PKGINFO" < "$PKG_DIR/.PKGINFO" < "$PKG_DIR/.PKGINFO" < "$APP_DIR/moltis.desktop" < "$APP_DIR/moltis.svg" <M SVG ln -sf moltis.svg "$APP_DIR/.DirIcon" cat > "$APP_DIR/AppRun" <<'APPRUN' #!/bin/sh SELF=$(readlink -f "$0") HERE=${SELF%/*} exec "$HERE/usr/bin/moltis" "$@" APPRUN chmod +x "$APP_DIR/AppRun" if [ ! -f target/appimagetool ]; then wget -q "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${ARCH}.AppImage" -O target/appimagetool chmod +x target/appimagetool fi ARCH=${ARCH} target/appimagetool --appimage-extract-and-run "$APP_DIR" "moltis-${VERSION}-${ARCH}.AppImage" echo "Built moltis-${VERSION}-${ARCH}.AppImage" # Build Snap package snap: snapcraft # Build Flatpak flatpak: cd flatpak && flatpak-builder --repo=repo --force-clean builddir org.moltbot.Moltis.yml # Run all CI checks (format, lint, build, test) ci: format-check lint i18n-check build-web-assets build test # Compile once, then run Rust tests and E2E tests in parallel. # Uses the same nightly toolchain as clippy/local-validate so the build cache # is shared — no double-compilation. build-test: build-web-assets #!/usr/bin/env bash set -euo pipefail echo "==> Building all workspace targets (bins + tests)..." if [ "$(uname -s)" = "Darwin" ]; then cargo +{{nightly_toolchain}} build --workspace --all-targets else cargo +{{nightly_toolchain}} build --workspace --all-features --all-targets fi just codesign-debug echo "==> Build complete. Running Rust tests and E2E tests in parallel..." RUST_LOG="$(mktemp)" E2E_LOG="$(mktemp)" trap 'rm -f "${RUST_LOG}" "${E2E_LOG}"' EXIT if [ "$(uname -s)" = "Darwin" ]; then cargo +{{nightly_toolchain}} nextest run --workspace > "${RUST_LOG}" 2>&1 & else cargo +{{nightly_toolchain}} nextest run --workspace --all-features > "${RUST_LOG}" 2>&1 & fi TEST_PID=$! (cd crates/web/ui && npm run e2e) > "${E2E_LOG}" 2>&1 & E2E_PID=$! TEST_EXIT=0; E2E_EXIT=0 wait "${TEST_PID}" || TEST_EXIT=$? wait "${E2E_PID}" || E2E_EXIT=$? if [ "${TEST_EXIT}" -ne 0 ]; then echo "==> Rust tests FAILED (exit ${TEST_EXIT}):" cat "${RUST_LOG}" else echo "==> Rust tests PASSED" fi if [ "${E2E_EXIT}" -ne 0 ]; then echo "==> E2E tests FAILED (exit ${E2E_EXIT}):" cat "${E2E_LOG}" else echo "==> E2E tests PASSED" fi exit $(( TEST_EXIT > 0 ? TEST_EXIT : E2E_EXIT )) # Run the same Rust preflight gates used before release packaging. release-preflight: lint cargo +{{nightly_toolchain}} fmt --all -- --check # Sync repo-root install.sh into website/install.sh for Cloudflare deployment. sync-website-install: ./scripts/sync-website-install.sh # Ensure repo-root install.sh and website/install.sh are identical. check-website-install-sync: ./scripts/check-website-install-sync.sh # Dispatch release workflow from GitHub Actions (normal mode). release-workflow ref='main': gh workflow run release.yml --ref {{ref}} -f dry_run=false # Dispatch release workflow from GitHub Actions (dry-run mode). release-workflow-dry ref='main': gh workflow run release.yml --ref {{ref}} -f dry_run=true # Dispatch both release workflow modes for the same ref (dry-run then normal). release-workflow-both ref='main': gh workflow run release.yml --ref {{ref}} -f dry_run=true gh workflow run release.yml --ref {{ref}} -f dry_run=false # Regenerate CHANGELOG.md from git history and tags. changelog: git-cliff --config cliff.toml --output CHANGELOG.md # Preview unreleased changelog entries from commits since the last tag. changelog-unreleased: git-cliff --config cliff.toml --unreleased # Generate release entries for unreleased commits under the provided version. changelog-release version: git-cliff --config cliff.toml --unreleased --tag "{{version}}" --strip all # Commit all changes, push branch, create/update PR, and run local validation. # All args are optional; defaults are auto-generated from branch + changed files. ship commit_message='' pr_title='' pr_body='': ./scripts/ship-pr.sh {{ quote(commit_message) }} {{ quote(pr_title) }} {{ quote(pr_body) }} # Run local validation with the full Rust and Playwright test suites. local-validate-full pr_number='': #!/usr/bin/env bash set -euo pipefail args=() if [[ -n {{ quote(pr_number) }} ]]; then args+=({{ quote(pr_number) }}) fi # `"${args[@]+...}"` is required: bash 3.2 (the default /bin/bash on macOS) # treats a plain `"${args[@]}"` on an empty array as an unbound variable # under `set -u`. The array is empty in the supported no-PR local-only mode. LOCAL_VALIDATE_TEST_CMD="just test" \ LOCAL_VALIDATE_E2E_CMD="cd crates/web/ui && npm run e2e:install && npm run e2e" \ ./scripts/local-validate.sh "${args[@]+"${args[@]}"}" # Run all tests (nightly to share build cache with clippy/lint, OS-aware). # On macOS: single nextest run using default features (includes Metal, not CUDA). # On Linux: --all-features (includes CUDA). # Builds first so codesign can run before test execution (prevents Little Snitch prompts). test: #!/usr/bin/env bash set -euo pipefail if [ "$(uname -s)" = "Darwin" ]; then cargo +{{nightly_toolchain}} build --workspace --all-targets just codesign-debug cargo +{{nightly_toolchain}} nextest run --workspace else cargo +{{nightly_toolchain}} nextest run --workspace --all-features fi # Run contract test suites (channel, provider, memory, tools) contract-tests: cargo test -p moltis-channels contract cargo test -p moltis-providers contract cargo test -p moltis-memory contract cargo test -p moltis-tools contract # Verify locale key parity across frontend i18n bundles. i18n-check: ./scripts/i18n-check.sh # Install browser tooling for gateway web UI e2e tests. ui-e2e-install: cd crates/web/ui && npm install && npm run e2e:install # Run gateway web UI e2e tests (Playwright). ui-e2e: cargo +{{nightly_toolchain}} build --bin moltis just codesign-debug cd crates/web/ui && npm run e2e # Run gateway web UI e2e tests with headed browser. ui-e2e-headed: cargo +{{nightly_toolchain}} build --bin moltis just codesign-debug cd crates/web/ui && npm run e2e:headed # Build all Linux packages (deb + rpm + arch + appimage) for all architectures packages-all: deb-all rpm-all arch-pkg-all # Build the native gpui desktop client (apps/desktop, its own workspace). desktop-build: cd apps/desktop && cargo build # Run the desktop client's tests. desktop-test: cd apps/desktop && cargo test # Lint the desktop client (all feature combinations it ships with). desktop-lint: cd apps/desktop && cargo clippy --all-targets --features mockup -- -D warnings cd apps/desktop && cargo clippy --all-targets --no-default-features -- -D warnings # Run the desktop client. desktop-run: cd apps/desktop && cargo run # Show UI variants from FILE side by side (the gpui-mockup agent skill). # Without FILE it shows the built-in demo (apps/desktop/src/mockup/demo.rs). desktop-mockup file="" feedback="" capture="": #!/usr/bin/env bash set -euo pipefail absolute() { case "$1" in ""|/*) printf '%s' "$1" ;; *) printf '%s/%s' {{quote(invocation_directory())}} "$1" ;; esac; } file="$(absolute {{quote(file)}})" feedback="$(absolute {{quote(feedback)}})" capture="$(absolute {{quote(capture)}})" cd apps/desktop MOLTIS_MOCKUP_FILE="$file" cargo build --locked --features mockup args=(--mockup) if [ -n "$feedback" ]; then args+=(--feedback "$feedback"); fi if [ -n "$capture" ]; then args+=(--capture "$capture"); fi exec target/debug/moltis-desktop "${args[@]}" # Package "Moltis Desktop.app" (macOS) with the moltis daemon inside. desktop-package-macos: ./scripts/package-desktop-macos.sh # Package the Moltis Desktop AppImage (Linux) with the moltis daemon inside. desktop-package-linux: ./scripts/package-desktop-linux.sh # Build "Moltis Desktop.app" with the moltis daemon inside (release) and open it. desktop-open-macos: desktop-package-macos open "apps/desktop/target/bundle/Moltis Desktop.app" # Build Rust static library and generated C header for the macOS app. swift-build-rust: ./scripts/build-swift-bridge.sh # Generate Xcode project from YAML spec in apps/macos. swift-generate: ./scripts/generate-swift-project.sh # Lint macOS app sources with SwiftLint. swift-lint: ./scripts/lint-swift.sh # Build Swift macOS app. swift-build: swift-build-rust swift-generate ./scripts/build-swift.sh # Run Swift app unit tests. swift-test: swift-build-rust swift-generate ./scripts/test-swift.sh # Build and launch the Swift macOS app locally. swift-run: swift-build-rust swift-generate ./scripts/run-swift.sh # Open generated project in Xcode. swift-open: swift-build-rust swift-generate open apps/macos/Moltis.xcodeproj # Generate iOS app Xcode project. ios-generate: ./scripts/generate-ios-project.sh # Generate Apollo GraphQL types for iOS. ios-graphql: cargo run -p moltis-schema-export -- apps/ios/GraphQL/Schema/schema.graphqls ./scripts/generate-ios-graphql.sh # Build iOS app (generic iOS destination, no signing). ios-build: ios-generate ios-graphql ./scripts/generate-ios-project.sh xcodebuild -project apps/ios/Moltis.xcodeproj -scheme Moltis -configuration Debug -destination "generic/platform=iOS" CODE_SIGNING_ALLOWED=NO build # Lint iOS app sources with SwiftLint. ios-lint: cd apps/ios && swiftlint # Open iOS project in Xcode (regenerates GraphQL types and project first). ios-open: ios-generate ios-graphql ./scripts/generate-ios-project.sh open apps/ios/Moltis.xcodeproj # Build the APNS push relay. courier-build: cargo build -p moltis-courier --release # Cross-compile courier for linux/x86_64. courier-cross: cargo build -p moltis-courier --release --target x86_64-unknown-linux-gnu # Deploy courier to remote server(s) via Ansible. courier-deploy: cd apps/courier/deploy && ansible-playbook playbook.yml # Run the APNS push relay (dev). courier-run *ARGS: cargo run -p moltis-courier -- {{ARGS}} # Serve the website locally with SSR partial injection (default 127.0.0.1:4000). website-dev: node website/scripts/build-changelog.mjs node website/scripts/dev-server.mjs