docs: retire ZeroClaw — reconcile docs + config to the post-#36 architecture#90
Merged
Conversation
content_filter() (bridge/text.py) already has the tier and the matched term in scope at every hit. Keep the last 20 hits in an in-memory ring and expose them at /ui/safety/recent. - bridge/text.py: _cf_recent deque (maxlen 20) + recent_content_filter_hits getter; content_filter appends (ts, tier, rule, 8-char prefix) per hit. In-memory only — never written to disk; no more exposed than the content-filter-hit log line already emitted. - dashboard.py: GET /ui/safety/recent. - safety_recent.html + a card in dashboard.html. (Supersedes the earlier "spec mismatch" re-triage — that was based on a wrong guess about where content_filter lives; it's a repo file.) Closes #72. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bring docs, CLAUDE.md, README, and the config templates in line with the #36 cutover — ZeroClaw and the RPi bridge retired; the brain is now a pi coding agent in the dotty-pi container, perception handled by dotty-behaviour, and bridge.py reduced to the dashboard service. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Completes the reconciliation in d4adb1d: - compose.all-in-one.yml: drop the dead zeroclaw-bridge service; it now brings up xiaozhi-server only and points at the dotty-pi / dotty-behaviour compose files. - mkdocs.yml + docs/README.md: drop the deleted multi-host / multi-daemon-split docs from nav and index. - pyproject.toml: remove the per-file lint rule for the deleted custom-providers/zeroclaw/zeroclaw.py. - bridge/requirements.txt: comment-only — drop the zeroclaw.py reference. - CHANGELOG.md: add the reconciliation entry. - brain.md / proactive-greetings.md: drop a phantom doc reference and correct the greeter state-file path to its real default. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in 5 commits that landed on main while the ZeroClaw-retirement doc sweep was in progress (#53 per-person memory, #74, #81 hardware-doc verification, #88 CI fix, the #87 dashboard-quick-wins merge). Conflicts resolved (2 files): - CLAUDE.md — kept the post-#36 architecture diagram and pi_voice Config-Files bullet over main's older ZeroClaw text. - docs/faq.md — combined main's verified servo spec (feedback servos, SCS0009 pitch) with the ZeroClaw-retirement fix to the brain-host line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the repository’s documentation and templates to match the post-#36 single-Docker-host architecture (PiVoiceLLM → dotty-pi, perception/ambient → dotty-behaviour, dashboard → bridge.py), and removes (some) ZeroClaw-era docs/provider code. It also includes an ops dashboard change (#72) adding a “recent content-filter hits” ring buffer panel.
Changes:
- Rewrites top-level docs and deep docs to describe the post-#36 container topology and updated endpoints/placeholders.
- Removes the legacy
custom-providers/zeroclaw/zeroclaw.pyprovider and deletes docs that described ZeroClaw multi-host/multi-daemon deployments. - Adds a new dashboard panel and backing in-memory ring buffer for recent content-filter hits (#72).
Reviewed changes
Copilot reviewed 53 out of 54 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| SETUP.md | Updates first-boot instructions and health checks for single-host/containerized services. |
| session-prompt.md | Updates the historical bootstrap prompt to the post-#36 single-host setup flow. |
| SECURITY.md | Adjusts threat-model wording and in-scope components for the new architecture. |
| ROADMAP.md | Reframes shipped features and work-in-progress notes around PiVoiceLLM/dotty-behaviour. |
| README.md | Updates project overview, topology, and links away from ZeroClaw. |
| pyproject.toml | Removes the now-obsolete lint ignore for the deleted ZeroClaw provider file. |
| monitoring/README.md | Rewords monitoring artifacts as targeting bridge.py dashboard service. |
| mkdocs.yml | Removes nav entry for deleted multi-host doc. |
| household.example.yaml | Updates suggested deploy path and hot-reload ownership to dotty-behaviour. |
| dotty-behaviour/README.md | Updates cutover notes and clarifies old vs new vision bridge URL wording. |
| dotty-behaviour/docker-compose.yml | Updates VISION_BRIDGE_URL guidance and networking notes. |
| docs/voice-pipeline.md | Rewrites pipeline summary around PiVoiceLLM + dotty-behaviour perception relay. |
| docs/troubleshooting.md | Updates troubleshooting steps for PiVoiceLLM/dotty containers and new endpoints. |
| docs/tier1slim.md | Repositions Tier1Slim as an alternate backend; notes escalation is non-functional post-cutover. |
| docs/style.md | Updates placeholder guidance away from <ZEROCLAW_*>. |
| docs/speaker-id-investigation.md | Updates provider references from zeroclaw → pi_voice. |
| docs/references.md | Updates canonical links, removes ACP links, adds dotty-pi/dotty-pi-ext references. |
| docs/README.md | Updates docs index and tree overview to new architecture and removes deleted docs. |
| docs/quickstart.md | Updates happy-path setup steps and deployment layout for the new stack. |
| docs/protocols.md | Replaces ACP section with pi RPC + splits HTTP APIs by service. |
| docs/proactive-greetings.md | Updates diagrams and paths to dotty-behaviour ownership. |
| docs/observability.md | Updates wording/commands to new service naming and target host placeholders. |
| docs/modes.md | Updates state/toggle backing-path descriptions to PiVoiceLLM + v2 smart-mode notes. |
| docs/llm-backends.md | Updates backend comparison: PiVoiceLLM default, Tier1Slim alternate, etc. |
| docs/latent-capabilities.md | Updates “brain unused” section for pi agent + dotty-pi-ext capabilities. |
| docs/kid-mode.md | Updates enforcement-layer descriptions for PiVoiceLLM vs Tier1Slim. |
| docs/interaction-map.md | Updates signal-flow map from zeroclaw-bridge to dotty-pi/dotty-behaviour. |
| docs/hardware-support.md | Updates server-side component list for the new stack. |
| docs/faq.md | Updates FAQs for new brain/provider model and container topology. |
| docs/cookbook/llama-swap-concurrent-models.md | Updates cross-link text to the new backend chooser doc. |
| docs/cookbook/disable-kid-mode.md | Updates restart instructions (bridge container wording). |
| docs/cookbook/change-persona.md | Updates persona ownership and removes ZeroClaw persona instructions. |
| docs/cookbook/add-emoji.md | Updates restart instructions (bridge container wording). |
| docs/brain.md | Rewrites “brain” doc from ZeroClaw to pi agent runtime + dotty-pi-ext tools. |
| docs/architecture.md | Rewrites topology and data-flow diagrams to the post-#36 single-host stack. |
| docs/advanced/variant-port-guide.md | Updates “server stack” wording and example endpoint hostnames. |
| docs/about.md | Updates high-level summary to two-layer emoji enforcement and pi-agent brain. |
| docker-compose.yml.template | Removes zeroclaw provider mount; repoints VISION_BRIDGE_URL to dotty-behaviour. |
| custom-providers/zeroclaw/zeroclaw.py | Deletes the legacy ZeroClawLLM xiaozhi provider implementation. |
| custom-providers/pi_voice/README.md | Updates status to “production” and notes bridge voice routes are retired. |
| CONTRIBUTING.md | Updates contribution guidance for placeholders and component areas post-#36. |
| compose.all-in-one.yml | Removes embedded bridge service; repositions file as xiaozhi-only convenience compose. |
| COMPATIBILITY.md | Updates compatibility matrix from ZeroClaw/ACP to dotty-pi + pi RPC + dotty-behaviour APIs. |
| CLAUDE.md | Updates repo orientation doc for the new architecture and providers. |
| CHANGELOG.md | Adds an Unreleased entry documenting this doc/config reconciliation and deletions. |
| bridge/text.py | Adds recent content-filter hit ring buffer (#72) and accessor function. |
| bridge/templates/safety_recent.html | New dashboard partial to render recent content-filter hits. |
| bridge/templates/dashboard.html | Adds a new dashboard card that auto-refreshes /ui/safety/recent. |
| bridge/requirements.txt | Updates header/comments to reflect dashboard service usage. |
| bridge/dashboard.py | Adds /ui/safety/recent endpoint for the recent-hit panel. |
| .config.yaml.template | Repoints vision_explain to dotty-behaviour and removes ZeroClawLLM config block. |
| docs/multi-daemon-split.md | Deletes obsolete ZeroClaw multi-daemon deployment doc. |
| docs/advanced/multi-host.md | Deletes obsolete multi-host (Docker host + ZeroClaw host) doc. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+159
to
+164
| _cf_recent.append({ | ||
| "ts": time.time(), | ||
| "tier": tier, | ||
| "rule": match.group(), | ||
| "prefix": text[:8], | ||
| }) |
| Both the bridge's `POST /admin/kid-mode` endpoint and the dashboard toggle persist the new value and call `_apply_kid_mode(enabled)`, which atomically re-binds every kid-mode-derived module global (`KID_MODE`, `VISION_SYSTEM_PROMPT`, `MCP_TOOL_DENYLIST`, `VOICE_TURN_SUFFIX`, `VOICE_TURN_SUFFIX_SHORT`) in a single store-global pass. Readers see either the old or new value, never a torn intermediate, and the cost per turn is unchanged. **No daemon restart is required** to flip kid-mode at runtime. | ||
|
|
||
| The xiaozhi-server side of kid-mode lives in the active LLM provider's persona / suffix. For `Tier1Slim`, `KID_MODE` is read at module import and baked into `_TURN_SUFFIX`; a flip there does currently require a container restart to take effect on Tier1Slim's side (the bridge side rebinds instantly, but the suffix already loaded into the live `Tier1Slim` instance is unchanged). For `ZeroClawLLM`, the suffix is generated per-turn by the bridge so the flip lands on the very next turn with no restart at all. | ||
| The xiaozhi-server side of kid-mode lives in the active LLM provider's persona / suffix. For `Tier1Slim`, `KID_MODE` is read at module import and baked into `_TURN_SUFFIX`; a flip there does currently require a container restart to take effect on Tier1Slim's side (the bridge side rebinds instantly, but the suffix already loaded into the live `Tier1Slim` instance is unchanged). For `PiVoiceLLM`, the persona is loaded per-session by the `dotty-pi` agent, so the flip lands on the very next turn with no restart at all. |
Comment on lines
+247
to
+249
| Each turn is a single JSONL object written to stdin; the agent streams JSONL response chunks back on stdout. Only TTS-bound text chunks are forwarded to xiaozhi-server — tool call details stay internal to the agent loop. The agent exits cleanly after each turn; `PiClient` re-invokes `docker exec` for the next turn. | ||
|
|
||
| ### `POST /api/voice/memory_log` — Tier1Slim turn log (fire-and-forget) | ||
| The dotty-pi agent loads the **dotty-pi-ext extension** at startup, which registers the five voice tools (`memory_lookup`, `remember`, `think_hard`, `take_photo`, `play_song`). Tool results never appear in the TTS stream. |
Comment on lines
+286
to
+290
| | Endpoint | Purpose | | ||
| |---|---| | ||
| | `GET /ui` | Admin dashboard web UI | | ||
| | `POST /admin/*` | Admin mutations (toggle, kid-mode, smart-mode, set-tier1slim-model, play-asset, etc.) | | ||
| | `GET /health` | Liveness probe; returns `{"ok": true}` | |
| #### `PiVoiceLLM` (default) | ||
|
|
||
| Custom provider at `custom-providers/tier1_slim/tier1_slim.py` (mounted into `/opt/xiaozhi-esp32-server/core/providers/llm/tier1_slim/`). Talks directly to a local llama-swap endpoint with a ~500-token system prompt and a four-tool catalogue (`memory_lookup`, `think_hard`, `take_photo`, `play_song`). Plain conversational turns are answered by the small inner-loop model (`qwen3.5:4b` by default) in well under 1 s warm — **no bridge round-trip**. | ||
| Custom provider at `custom-providers/pi_voice/` (mounted into `/opt/xiaozhi-esp32-server/core/providers/llm/pi_voice/`). It doesn't run a model itself — it hands each voice turn to the **`dotty-pi` container** by running `docker exec -i dotty-pi pi --mode rpc` and exchanging JSONL messages over stdio. The pi agent owns the conversation loop (`qwen3.5:4b` on local llama-swap) and the five `dotty-pi-ext` voice tools (`memory_lookup`, `remember`, `think_hard`, `take_photo`, `play_song`); only TTS-bound text streams back. See [brain.md](./brain.md). |
Comment on lines
182
to
188
| 2. **Voice round-trip** — speak a simple phrase and confirm ASR → LLM → TTS returns audio to the device. | ||
| 3. **MCP tool call** — send a test instruction through the bridge: | ||
| ```bash | ||
| curl -X POST http://<ZEROCLAW_HOST>:8080/api/message \ | ||
| curl -X POST http://<XIAOZHI_HOST>:8080/api/message \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"content":"Turn your head to the right"}' | ||
| ``` |
Comment on lines
+80
to
+85
| `bridge.py` was the original HTTP→ZeroClaw translator, running under systemd on the RPi. Post-cutover (#36) it runs as a Docker container on the same Docker host, port 8080. Its **voice path** (`/api/message`, `/api/voice/*`) and **perception relay** (`/api/perception/event`) roles are retired — those functions moved to `PiVoiceLLM`/`dotty-pi` and `dotty-behaviour`. What remains: | ||
|
|
||
| Lives at `<BRIDGE_PATH>/bridge.py`, runs under systemd (`zeroclaw-bridge.service`). | ||
| - **Admin dashboard** (`/ui`) — the operator web UI for monitoring turns, toggling kid-mode/smart-mode, viewing scene context, and LED state. | ||
| - **`/admin/*` endpoints** (localhost-only) — runtime toggles for kid-mode, smart-mode, safety allowlist. | ||
|
|
||
| **HTTP surface:** | ||
| A dashboard port to `dotty-behaviour` is still pending; until then, bridge.py's dashboard panels that relied on the bridge's own perception bus may show stale or empty data. |
Comment on lines
+43
to
+44
| | pi agent (dotty-pi) | https://github.com/BrettKinny/dotty-stackchan/tree/main/dotty-pi | The Docker container that runs the pi coding agent — the current Dotty brain. | | ||
| | dotty-pi-ext | https://github.com/BrettKinny/dotty-stackchan/tree/main/dotty-pi-ext | pi extension providing the 5 voice tools (memory_lookup, remember, think_hard, take_photo, play_song). | |
Comment on lines
14
to
+17
| # Port 8090 (not the bridge's 8080) — llama-swap owns 8080 on Unraid. | ||
| # xiaozhi-server's VISION_BRIDGE_URL must move from | ||
| # http://<ZEROCLAW_HOST>:8080 → http://localhost:8090 at cutover. | ||
| # xiaozhi-server's VISION_BRIDGE_URL must point to | ||
| # http://<XIAOZHI_HOST>:8090 (the Unraid LAN IP — loopback works only | ||
| # if xiaozhi-server is also on host networking). |
Comment on lines
+888
to
+908
| @router.get("/safety/recent", response_class=HTMLResponse, include_in_schema=False) | ||
| async def safety_recent(request: Request) -> Any: | ||
| """#72 — recent content-filter hits from the in-memory ring (last 20). | ||
| In-memory only; empties on a bridge restart.""" | ||
| from bridge.text import recent_content_filter_hits | ||
| rows: list[dict[str, Any]] = [] | ||
| for hit in recent_content_filter_hits(): | ||
| ts = hit.get("ts") or 0 | ||
| try: | ||
| time_str = datetime.fromtimestamp(ts).astimezone().strftime("%H:%M:%S") | ||
| except Exception: | ||
| time_str = "?" | ||
| rows.append({ | ||
| "time": time_str, | ||
| "tier": hit.get("tier") or "?", | ||
| "rule": hit.get("rule") or "", | ||
| "prefix": hit.get("prefix") or "", | ||
| }) | ||
| return templates.TemplateResponse( | ||
| request, "safety_recent.html", {"rows": rows}, | ||
| ) |
`custom-providers/zeroclaw/` was retired in the cutover but the unit-test file outlived it. At pytest collection time the test loaded `zeroclaw.py` via importlib and raised FileNotFoundError, aborting the whole suite (CI Python Tests on #90). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The
#36cutover (executed 2026-05-19) replaced the RPi-hostedzeroclaw-bridge+ ZeroClaw agent with two containers —dotty-pi(the pi-agent brain) anddotty-behaviour(perception bus + ambient consumers + greeter). The cutover runbook explicitly deferred the documentation follow-up; this PR is that follow-up. README, CLAUDE.md, the config templates, and the wholedocs/tree previously described the dead RPi/ZeroClaw topology — they now describe the live stack.Changes
Deleted
custom-providers/zeroclaw/— the deadZeroClawLLMproviderdocs/multi-daemon-split.md,docs/advanced/multi-host.md— documented ZeroClaw-host topologies that no longer existRewritten to the post-#36 architecture
README.md,CLAUDE.md,.config.yaml.template,docker-compose.yml.template,compose.all-in-one.ymlarchitecture,brain,llm-backends,protocols,tier1slim,quickstart,SETUP,session-prompt,faq,interaction-map,COMPATIBILITY,voice-pipeline, plus the long tail (kid-mode,troubleshooting,modes,observability,references, cookbook, …)vision_explain/VISION_BRIDGE_URLrepointed todotty-behaviour:8090;zeroclawprovider mount +ZeroClawLLMconfig block removedKept (deliberately)
bridge.py/bridge/— still live as the admin dashboard service (:8080/ui); only its voice/perception roles were retiredTier1Slim— documented as an alternate backend; escalation is non-functional post-cutover, so docs describe it honestly as a chitchat-only rollbackscripts/install-bridge.sh,scripts/deploy-bridge.sh,zeroclaw-bridge.service.template— dead RPi artifacts, retained by maintainer decisionVerification
ZeroClaw/ACPstring is an intentional past-tense cutover/historical noteorigin/mainNotes for the reviewer
be105cf #72: dashboard — content-filter recent-hits ring— that was committed onto this branch and missed PR dashboard: quick-wins batch (#69, #64, #74) #87.#53 per-person memory(merged tomainmid-work) addedremember_person/recall_persontools todotty-pi-ext; docs here still say "five voice tools" — minor follow-up.🤖 Generated with Claude Code