feat(uno-q): LAN-open boot + Telegram self-serve + guided lockdown modalities

Boards now boot LAN-open (host 0.0.0.0, allow_public_bind, require_pairing=false)
so a team reaches its node's embedded ZeroClaw dashboard + web chat directly by
IP with no token — the 'Open your node' path. Two more modalities ride the same
default (cloud-first) agent:

- Telegram: config seeds [channels.telegram.default] disabled + pre-bound to the
  default agent; a team enables it from the dashboard by pasting a @BotFather
  token. Dashboard writes only set pending_reload, and /admin/reload is
  loopback-only, so a new zeroclaw-reload-watcher.sh (loopback) applies dashboard
  config edits within seconds — no shell. provision-fleet pushes + launches it.
- Lockdown: zeroclaw-lockdown.sh flips require_pairing=true, reloads, and mints a
  pair code (open -> locked harden step); documented as a board/adb action since
  minting + reload are loopback-only.
- Voice: seeds a commented [channels.voice_duplex.default] + documents the
  aarch64 build (embedded-web + gateway-voice-duplex); build/hardware work is
  separate.

Onboarding scripts (apess-selfregister.sh, provision-uno-q.sh) now tolerate
open-boot: when the gateway mints no pair code, they announce with a placeholder
token (the open board ignores auth) instead of hard-failing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Omar Sobh
2026-07-15 16:35:28 -07:00
co-authored by Claude Opus 4.8
parent af9cae0abc
commit 7233a4b1c0
8 changed files with 273 additions and 24 deletions
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# On-board reload-watcher. The ZeroClaw dashboard lets a team edit config from
# their browser (enable their Telegram bot, set allowed_users, …) — but a config
# write only sets `pending_reload`; the channel listeners don't re-spawn until
# `POST /admin/reload`, which is LOOPBACK-ONLY. A LAN browser can't call it.
#
# This watcher closes that gap: it runs on the board, notices when config.toml
# changes, and fires the loopback reload — so a team's dashboard edit takes
# effect on its own within a few seconds, no shell required. It's the thing that
# makes browser self-serve (Telegram, and the lockdown flip) actually work.
#
# ./zeroclaw-reload-watcher.sh # loops; run via setsid or systemd
#
# Env:
# ZC_CONFIG config file to watch (default /home/arduino/.zeroclaw/config.toml)
# GATEWAY_PORT loopback gateway port (default 8080)
# POLL_SECS poll interval (default 3)
# SETTLE_SECS debounce after a change before reloading (default 2)
set -uo pipefail
CONFIG="${ZC_CONFIG:-/home/arduino/.zeroclaw/config.toml}"
PORT="${GATEWAY_PORT:-8080}"
POLL="${POLL_SECS:-3}"
SETTLE="${SETTLE_SECS:-2}"
BASE="http://127.0.0.1:${PORT}"
mtime() { stat -c %Y "$CONFIG" 2>/dev/null || echo 0; }
reload() { # loopback → passes the gateway's require_localhost gate
curl -sf --max-time 5 -X POST "${BASE}/admin/reload" >/dev/null 2>&1
}
echo "[reload-watcher] watching $CONFIG${BASE}/admin/reload (poll ${POLL}s)"
last="$(mtime)"
while :; do
sleep "$POLL"
cur="$(mtime)"
[ "$cur" = "$last" ] && continue
# config changed — let a burst of per-field writes settle, then reload once
sleep "$SETTLE"
cur="$(mtime)"
if reload; then
echo "[reload-watcher] config changed → reloaded daemon ($(date -u +%H:%M:%SZ))"
else
echo "[reload-watcher] config changed → reload failed (daemon down?); will retry"
fi
last="$cur"
done