#!/usr/bin/env bash # # Install joule-coded as a launchd *user agent* in the GUI (Aqua) domain. # # Why the GUI domain and not `nohup … &`: on macOS a process detached from a # login session is denied permission to *initiate* outbound local-network # connections (it can still bind/accept). The headless worker's federation # transport (Phase 3) needs to dial peers, so it must run session-attached or as # a launchd agent in the GUI domain. `launchctl bootstrap gui/$(id -u)` gives it # that context; `nohup`-over-SSH does not (we root-caused this — see # open-standards lockstep-quic/MACOS_LAUNCH_CONTEXT.md). # # Usage: # JOULE_CODE_ROOT=/path/to/repo \ # JOULECLAW_L3_MODEL=/path/to/model.gguf \ # optional; enables the L3 tier # ./install-joule-coded.sh # # Override any of: JOULE_CODED_BIN, JOULE_CODE_ROOT, JOULE_CODE_SOCK, # JOULECLAW_L3_MODEL, JOULE_CODE_GRANT_TIERS. set -euo pipefail LABEL="dev.openie.joule-coded" HERE="$(cd "$(dirname "$0")" && pwd)" # Resolve the binary: an explicit override, else the repo's release/debug build. REPO_ROOT="$(cd "$HERE/../../.." && pwd)" BIN="${JOULE_CODED_BIN:-}" if [ -z "$BIN" ]; then for candidate in "$REPO_ROOT/target/release/joule-coded" "$REPO_ROOT/target/debug/joule-coded"; do [ -x "$candidate" ] && BIN="$candidate" && break done fi if [ -z "$BIN" ] || [ ! -x "$BIN" ]; then echo "error: joule-coded binary not found; build it (cargo build -p joule_coded) or set JOULE_CODED_BIN" >&2 exit 1 fi ROOT="${JOULE_CODE_ROOT:-$PWD}" SOCK="${JOULE_CODE_SOCK:-$HOME/.joule/joule-coded.sock}" TIERS="${JOULE_CODE_GRANT_TIERS:-l0,l1,l2,l3}" MODEL="${JOULECLAW_L3_MODEL:-}" DEST="$HOME/Library/LaunchAgents/$LABEL.plist" mkdir -p "$HOME/logs" "$(dirname "$SOCK")" "$HOME/Library/LaunchAgents" # The L3 model is optional: included only when a path is given. MODEL_ARGS="" if [ -n "$MODEL" ]; then MODEL_ARGS=" --model $MODEL " fi cat > "$DEST" < Label $LABEL ProgramArguments $BIN serve --root $ROOT --sock $SOCK --tiers $TIERS $MODEL_ARGS WorkingDirectory $ROOT EnvironmentVariables PATH /opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin HOME $HOME RUST_LOG info RunAtLoad KeepAlive SuccessfulExit Crashed ThrottleInterval 10 StandardOutPath $HOME/logs/joule-coded.out.log StandardErrorPath $HOME/logs/joule-coded.err.log PLIST # (Re)load into the GUI domain. DOMAIN="gui/$(id -u)" launchctl bootout "$DOMAIN/$LABEL" 2>/dev/null || true launchctl bootstrap "$DOMAIN" "$DEST" launchctl kickstart -k "$DOMAIN/$LABEL" echo "installed $LABEL" echo " binary : $BIN" echo " root : $ROOT" echo " sock : $SOCK" echo " model : ${MODEL:-}" echo "drive it: joule-coded fleet | joule-coded status --sock $SOCK" echo "uninstall: launchctl bootout $DOMAIN/$LABEL && rm $DEST"