diff --git a/build.sh b/build.sh index 2b3ea457..4f7eca92 100755 --- a/build.sh +++ b/build.sh @@ -1649,6 +1649,12 @@ EOF "${MOUNT_POINT}/usr/local/share/applications/Clawdie Join Hive.desktop" install -m 0644 "${LIVE_SESSION_DIR}/clawdie-join-hive.desktop" \ "${MOUNT_POINT}/home/clawdie/Desktop/Join Hive.desktop" + install -m 0755 "${LIVE_SESSION_DIR}/clawdie-enable-mother.sh" \ + "${MOUNT_POINT}/usr/local/bin/clawdie-enable-mother" + install -m 0644 "${LIVE_SESSION_DIR}/clawdie-enable-mother.desktop" \ + "${MOUNT_POINT}/usr/local/share/applications/Clawdie Enable Mother.desktop" + install -m 0644 "${LIVE_SESSION_DIR}/clawdie-enable-mother.desktop" \ + "${MOUNT_POINT}/home/clawdie/Desktop/Enable Mother Link.desktop" mkdir -p "${MOUNT_POINT}/usr/local/share/clawdie-iso/bootstrap" install -m 0644 "${LIVE_SESSION_DIR}/bootstrap.html" \ "${MOUNT_POINT}/usr/local/share/clawdie-iso/bootstrap/index.html" diff --git a/live/operator-session/clawdie-enable-mother.desktop b/live/operator-session/clawdie-enable-mother.desktop new file mode 100644 index 00000000..fa4f33ba --- /dev/null +++ b/live/operator-session/clawdie-enable-mother.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Version=1.0 +Name=Enable Mother Link +Comment=Let this agent's Pi call mother's tools over MCP (opt-in) +Exec=xfce4-terminal --title "Enable Mother Link" --geometry=90x28 --command "/usr/local/bin/clawdie-enable-mother" +Icon=network-transmit-receive +Terminal=false +Categories=System;Utility; diff --git a/live/operator-session/clawdie-enable-mother.sh b/live/operator-session/clawdie-enable-mother.sh new file mode 100755 index 00000000..a53d83fa --- /dev/null +++ b/live/operator-session/clawdie-enable-mother.sh @@ -0,0 +1,102 @@ +#!/bin/sh +# Enable the opt-in MCP link to "mother". +# +# Direction: this agent's Pi calls mother's tools. colibri-mcp dials OUT to +# mother over SSH-stdio and proxies mother's MCP tools to the Pi via its +# external-call path. Off by default; this script turns it on. +# +# The colibri daemon (and the Pi it spawns) run as the `colibri` user, so the +# outbound SSH uses an identity in the colibri home (/var/db/colibri/.ssh). +# Run this in a visible terminal so the operator can copy the public key. + +set -eu + +PROVIDER_ENV="/usr/local/etc/colibri/provider.env" +EXTERNAL_MCP="/usr/local/etc/colibri/external-mcp.json" +COLIBRI_HOME="/var/db/colibri" +SSH_KEY="${COLIBRI_HOME}/.ssh/id_ed25519" + +finish() { + echo "" + echo "Press Enter to close." + read -r _ + exit "${1:-0}" +} + +have() { + command -v "$1" >/dev/null 2>&1 +} + +if ! have mdo; then + echo "ERROR: mdo is required to update the colibri service configuration." + finish 1 +fi + +echo "========================================" +echo " Clawdie — Enable Mother Link" +echo "========================================" +echo "" + +# 1. Mother's reachable address + remote MCP command. +printf " Mother SSH target (user@tailscale-ip-or-name): " +read -r MOTHER_HOST +if [ -z "${MOTHER_HOST:-}" ]; then + echo " Cancelled: no mother target entered." + finish 0 +fi +printf " Mother MCP command [colibri-mcp]: " +read -r MOTHER_CMD +[ -n "${MOTHER_CMD:-}" ] || MOTHER_CMD="colibri-mcp" + +# 2. Ensure the colibri service account has an SSH key for the outbound link. +echo "" +echo "[1/4] Ensuring colibri SSH identity..." +mdo -u root sh -c ' + set -eu + home="$1"; key="$2" + install -d -o colibri -g colibri -m 0700 "${home}/.ssh" + if [ ! -f "$key" ]; then + ssh-keygen -t ed25519 -N "" -f "$key" -C "colibri@$(hostname)" >/dev/null + chown colibri:colibri "$key" "${key}.pub" + chmod 0600 "$key"; chmod 0644 "${key}.pub" + fi +' sh "$COLIBRI_HOME" "$SSH_KEY" + +# 3. Write the mother entry into the external MCP registry. +echo "[2/4] Registering mother in ${EXTERNAL_MCP}..." +printf '%s\n' "{ + \"servers\": { + \"mother\": { + \"command\": \"ssh\", + \"args\": [\"-i\", \"${SSH_KEY}\", \"-o\", \"BatchMode=yes\", \"-o\", \"StrictHostKeyChecking=accept-new\", \"${MOTHER_HOST}\", \"${MOTHER_CMD}\"], + \"env\": {} + } + } +}" | mdo -u root sh -c 'cat > "$1"; chmod 0644 "$1"' sh "$EXTERNAL_MCP" + +# 4. Allow external MCP calls: upsert COLIBRI_MCP_EXTERNAL_CALL=1 into provider.env. +echo "[3/4] Enabling external MCP calls..." +mdo -u root sh -c ' + set -eu + f="$1" + tmp="$(mktemp)" + grep -v "^COLIBRI_MCP_EXTERNAL_CALL=" "$f" >"$tmp" 2>/dev/null || : + printf "COLIBRI_MCP_EXTERNAL_CALL=\"1\"\n" >>"$tmp" + cat "$tmp" >"$f" + rm -f "$tmp" + chmod 0600 "$f" +' sh "$PROVIDER_ENV" + +# 5. Restart the daemon so the Pi inherits the new env + registry. +echo "[4/4] Restarting colibri daemon..." +mdo -u root service colibri_daemon restart >/dev/null 2>&1 || + echo " WARNING: restart failed; run: mdo -u root service colibri_daemon restart" + +echo "" +echo "Mother link configured. Authorize this key on mother (restrict it to the" +echo "MCP command, e.g. command=\"${MOTHER_CMD}\",restrict in authorized_keys):" +echo "" +mdo -u root cat "${SSH_KEY}.pub" 2>/dev/null || echo " (could not read ${SSH_KEY}.pub)" +echo "" +echo "Once authorized on mother, the Pi can call mother's tools via colibri-mcp." +finish 0 diff --git a/scripts/stage-colibri-iso.sh b/scripts/stage-colibri-iso.sh index b4eae329..1be0ac59 100755 --- a/scripts/stage-colibri-iso.sh +++ b/scripts/stage-colibri-iso.sh @@ -112,9 +112,25 @@ cat > "${ETC_DIR}/provider.env" <<'EOF' # provider keys and Vaultwarden bootstrap credentials here after boot. VAULT_SERVER="https://vault.smilepowered.org" BW_SERVER="https://vault.smilepowered.org" + +# Auto-spawn one Pi agent on daemon startup once a DeepSeek key is present +# (the Operator Image OOTB flow). The daemon sources this file, so the spawned +# Pi inherits the provider keys set here. +COLIBRI_AUTOSPAWN_PI="YES" EOF chmod 0600 "${ETC_DIR}/provider.env" 2>/dev/null || true +# External MCP server registry — empty by default. The "Enable Mother Link" +# action (clawdie-enable-mother) adds a server entry here; colibri-mcp reads it +# when launched with COLIBRI_MCP_EXTERNAL_CALL=1. Path matches colibri-mcp's +# default COLIBRI_MCP_EXTERNAL_CONFIG. +cat > "${ETC_DIR}/external-mcp.json" <<'EOF' +{ + "servers": {} +} +EOF +chmod 0644 "${ETC_DIR}/external-mcp.json" 2>/dev/null || true + cat > "${ETC_DIR}/provider.env.sample" <<'EOF' # Optional provider keys and Vaultwarden bootstrap credentials for # colibri_daemon. The ISO already stages provider.env with the non-secret @@ -138,6 +154,14 @@ BW_SERVER="https://vault.smilepowered.org" # Optional endpoints/models: # DEEPSEEK_ENDPOINT="https://api.deepseek.com/chat/completions" # DEEPSEEK_MODEL="deepseek-chat" +# +# Behavior toggles (non-secret): +# COLIBRI_AUTOSPAWN_PI="YES" # auto-spawn one Pi on daemon startup +# COLIBRI_PI_BINARY="pi" # Pi executable name/path +# COLIBRI_AUTOSPAWN_PI_ARGS="--mode json" # Pi argv +# COLIBRI_MCP_EXTERNAL_CALL="1" # allow Pi (via colibri-mcp) to call +# # external MCP servers; set by +# # clawdie-enable-mother EOF cat > "${ETC_DIR}/README.iso" <<'EOF'