Files
apress/deploy/uno-q/config.template.toml
T
Omar SobhandClaude Opus 4.8 3be44ec215 Merge feat/uno-q-cross-build-deploy: resilience theater UI + cross-build helper
Folds the last unmerged workshop work into main:
- ResiliencePanel — the failure-injection 'theater' UI (cloud outage → on-board
  Qwen live demo) that visualizes the [agents.chaos] (custom.dead → llamacpp)
  failover, plus Module2 integration + api/nodes support.
- build-deploy.sh — one-command aarch64-musl cross-build + adb deploy helper,
  REFRESHED for 0.8.3: adds the web SPA prebuild step and the full feature set
  (hardware, peripheral-rpi, embedded-web, gateway-voice-duplex) + the
  embedded-web/web_dist_dir gotcha.

Config conflict resolved as a union: the branch's custom.dead + [agents.chaos]
demo blocks alongside this session's channels/voice/skills/risk-profile edits.
Verified: tsc clean, web 229 + api 58 tests green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-16 13:12:01 -07:00

146 lines
6.2 KiB
TOML

schema_version = 3
# ---------------------------------------------------------------------------
# Providers
# ---------------------------------------------------------------------------
# "cloud" primary. During bring-up this points at the local claude_shim
# (adb-reverse tunnel on :8090). For a real fleet, swap in a shared cloud
# endpoint + key, e.g.:
# uri = "https://api.anthropic.com/v1" (or an OpenRouter/LiteLLM gateway)
# api_key = "..." (prefer an env-injected key)
[providers.models.custom.cloud]
uri = "__CLOUD_URI__"
model = "__CLOUD_MODEL__"
native_tools = false
# Same cloud endpoint, but with an on-board Qwen fallback ("cloud first,
# local if it fails"). Used by the `default` agent.
[providers.models.custom.claude]
uri = "__CLOUD_URI__"
model = "__CLOUD_MODEL__"
native_tools = false
fallback = ["llamacpp.local"]
# A deliberately-dead cloud endpoint (nothing listens on :9099) that fails over
# to the on-board Qwen. Used by the `chaos` agent to DEMONSTRATE resilience: a
# prompt routed here always finds the cloud unreachable and answers locally —
# the "simulate cloud outage" button in APESS (Module 2, failure modes / L4).
[providers.models.custom.dead]
uri = "http://127.0.0.1:9099/v1"
model = "__CLOUD_MODEL__"
native_tools = false
fallback = ["llamacpp.local"]
[providers.models.llamacpp]
# On-board Qwen via llama-server (see zeroclaw-llama.service).
[providers.models.llamacpp.local]
uri = "http://127.0.0.1:8083/v1"
model = "qwen"
native_tools = false
[providers.models.custom]
# ---------------------------------------------------------------------------
# Hardware — the Uno Q's onboard MCU over the GPIO bridge.
# ---------------------------------------------------------------------------
[[peripherals.boards]]
board = "arduino-uno-q"
transport = "bridge"
[peripherals]
enabled = true
# ---------------------------------------------------------------------------
# Gateway — the HTTP/WS/SSE surface APESS talks to, AND the embedded web
# dashboard + chat UI a team opens directly at http://<board-lan-ip>:8080.
# ---------------------------------------------------------------------------
[gateway]
port = 8080
# LAN-open by default: participants reach the board's WiFi IP directly (the
# "Open your node →" link in APESS). 0.0.0.0 + allow_public_bind make the
# dashboard/web-chat reachable across the workshop subnet.
host = "0.0.0.0"
allow_public_bind = true
# Open during SETUP so a team's browser can chat + edit config (paste a Telegram
# token, etc.) with no token on the isolated workshop LAN. The reload-watcher
# (loopback) applies any dashboard config edit. Run `zeroclaw-lockdown.sh` to
# flip this on and mint a pair code once a team has finished setting up.
require_pairing = false
# paired_tokens are added by the pairing flow (lockdown / provision-uno-q.sh);
# never commit a real token.
[skills]
prompt_injection_mode = "compact"
# ---------------------------------------------------------------------------
# Risk profile — only the on-board hardware tools, auto-approved so the agent
# can flash without a human in the loop.
# ---------------------------------------------------------------------------
# read_skill + file_read are allowed AND auto-approved so agents can load the
# bundled skills (e.g. arduino-uno-q) and read their references/*.md on demand
# without a human approver (the webhook path is non-interactive).
[risk_profiles.default]
level = "supervised"
allowed_tools = ["uno_q_flash", "sysfs_led", "camera", "network", "i2cdetect", "read_skill", "file_read", "content_search"]
auto_approve = ["uno_q_flash", "sysfs_led", "camera", "network", "i2cdetect", "read_skill", "file_read", "content_search"]
[runtime_profiles.unoq]
agentic = true
max_tool_iterations = 6
strict_tool_parsing = false
# ---------------------------------------------------------------------------
# Agents — one per provider strategy. The APESS harness choice routes here via
# ?agent= (see harnessToAgent in src/lib/harness.ts).
# ---------------------------------------------------------------------------
[agents.default] # cloud + on-board Qwen fallback — the workshop default
enabled = true
model_provider = "custom.claude"
risk_profile = "default"
runtime_profile = "unoq"
# Modalities this agent answers on, beyond the APESS proxy + web chat: the team's
# own Telegram bot. A team enables it from the dashboard (Config → channels →
# telegram) by pasting their @BotFather token; the reload-watcher applies it.
channels = ["telegram.default"]
[agents.cloud] # cloud only, no fallback
enabled = true
model_provider = "custom.cloud"
risk_profile = "default"
runtime_profile = "unoq"
[agents.local] # on-board Qwen only (fully offline)
enabled = true
model_provider = "llamacpp.local"
risk_profile = "default"
runtime_profile = "unoq"
# ---------------------------------------------------------------------------
# Channels — extra ways a team talks to its node (all bind to `default`, above).
# ---------------------------------------------------------------------------
# Telegram: each board is its own agent, so each needs its own bot. A team
# creates one live via @BotFather, then pastes the token in the dashboard
# (Config → channels → telegram.default), sets enabled = true, and adds their
# Telegram username to allowed_users. The reload-watcher restarts the listener.
# Seeded disabled so the block shows up pre-bound in the config editor.
[channels.telegram.default]
enabled = false
bot_token = "" # from @BotFather (paste via the dashboard)
# allowed_users = ["your_tg_username"] # lock the bot to your team (no leading @)
mention_only = false
# Browser-mic streaming voice — talk to the agent inside the web chat, it speaks
# back. Requires a daemon built with the voice feature (see README §Voice):
# cargo xtask web build && cargo build --release \
# --features "hardware,peripheral-rpi,embedded-web,zeroclaw-gateway/gateway-voice-duplex"
# Enable once the board runs a voice-capable binary:
# [channels.voice_duplex.default]
# enabled = true
[agents.chaos] # simulated cloud outage → falls back to on-board Qwen
enabled = true
model_provider = "custom.dead"
risk_profile = "default"
runtime_profile = "unoq"