#!/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"