Move sections to where they read better:
- Phase 1 (Team registration): drop the "Your Agent" block.
- Phase 2 (Meet your agent): host the "Your Agent" section (say-hi / Telegram /
voice) AND the agent chat under it; remove "Pick your domain".
- Module 1 (Domain & events): "Pick your domain" moves here (no more read-only
carry) alongside the ADD Layer 1 card.
- Module 2 (Skills & policies): the chat is gone; the L2/L3 ADD cards show
directly (still auto-prefilled if the three prompts ran in Meet your agent).
Also: OpenYourNode opens the browser-reachable board URL. In self-host/USB mode
the stored url is container-facing (host.docker.internal) which the browser
can't resolve — derive the current host on :8080 instead. Tests updated.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Say-hi, the module chat, and Refine each hard-coded the 'cloud' agent
while Telegram ran on 'demo' — different agents for web vs Telegram, easy
to get wrong. Introduce a single `AGENT = 'default'` in api.ts and use it
everywhere. 'default' is the node's fallback agent (the one used when no
alias is given), fully loaded with the cloud model + all skills + all
tools — so no call site can pick a different or missing agent.
Board side (config): 'default' is now the sole enabled agent and owns the
telegram.default channel; 'cloud' and 'demo' are disabled and any stray
request for them falls back to 'default'.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The board is now a Claude-powered ZeroClaw agent with expert skills that teams
talk to directly (its own dashboard / Telegram / voice). The frontend was built
on the older sensor+harness model; this repoints it.
- State/DTO: AddLayers remapped to the 5 design layers (Domain/Skills/Policies/
Harness/Loops); added session.domain (+ mirrored through TeamSnapshot, sync,
and the SQLite store with a guarded migration); dropped Harness/Provider/RunMode;
persist v2 migrate resets stale state.
- Removed the harness/sim/failover machinery (HarnessProviderSelect, HarnessTuner,
HarnessTomlPreview, ResiliencePanel, TriggerButtons, harness.ts, useSerial,
LiveFeed/serial classifier) and every sim-vs-live branch.
- Onboarding: EnvSetup rebuilt into 'Meet your node' — Open-your-node hero (new
reusable OpenYourNode CTA), say-hi-to-your-agent, a free-text DomainPicker
(domain drives L1-L5), Telegram/voice pointers, and the open->locked lockdown
policy step. Domain is required to proceed.
- Modules repointed: M1 Domain & events (L1), M2 Skills & Policies (L2/L3, skills
reference + actuation-gate framing), M3 Harness (reasoning+tiering) & Loops
(cadence) (L4/L5). BuildFlash reframed as a guided 'ask your node to build X'
that hands off to the node dashboard.
- Judge rubric -> Domain fit/Skills/Policies/Harness/Loops; Lecture + Landing
re-storied to the Claude-node + talk-to-your-node narrative.
Verified: web tsc + 181 tests, api tsc + 58 tests, dead-ref sweep clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Close the tune→deploy loop without live config mutation. The gateway
already supports per-request `?agent=` selection, so map the harness to a
pre-provisioned agent alias and route the prompt to it:
- local primary → `local` (on-board Qwen only)
- cloud primary + fallback → `default` (cloud + Qwen fallback)
- cloud primary, no fallback→ `cloud` (cloud only)
- lib/harness: harnessToAgent(h).
- api: sendPrompt(node, msg, agent?) → `?agent=`; bridge.prompt +
POST /nodes/:teamId/prompt accept an optional `agent`.
- lib/api.sendPrompt(teamId, msg, agent?); BuildFlash derives the alias
from the live harness.
Boards must be provisioned with the `default`/`cloud`/`local` aliases
(our board currently has `default`); that lands with the provisioning kit.
Tests: front-end 180, api 29, typecheck clean, prod build passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Turn the workshop shell into a real on-device agent platform: APESS now
proxies each team's Arduino Uno Q (running ZeroClaw) and drives
generate → compile → flash from the UI, with a simulation fallback.
api — node backbone
- nodes.ts: team→node registry, a pure ZeroClaw /api/events → WsEvent
mapper, per-node live SSE subscription fanned out to the collective hub
AND per-team participant listeners, and a prompt proxy. Bearer tokens
stay server-side; list()/broadcasts never expose them.
- routes: POST/GET/DELETE /nodes (register is admin-only), public
POST /nodes/:teamId/prompt, and a participant-scoped SSE
GET /nodes/:teamId/events.
- WsEvent gains node:status / node:activity.
front-end
- session store: mode 'live' | 'sim' (default sim); a 'local' provider
and a harness.fallbackLocal toggle ("cloud first, on-board Qwen if it
fails") reflected in the harness.toml preview.
- EnvSetup: Simulation / Live board toggle — sim runs a virtual board
(self-test + Proceed with no hardware), live requires a registered node.
- BuildFlash panel (in Module 2): prompt the board, watch activity stream
live (SSE) or a simulated generate→flash sequence.
- lib/api: sendPrompt + openTeamActivity (EventSource).
housekeeping
- better-sqlite3 → 12.11 (Node 26 support; the 11.x native build fails on
Node 26's V8).
- vitest excludes the vendored Uno-QClaw/ tree.
Tests: front-end 172, api 29, typecheck clean, prod build passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>