#16: ZeroClaw cleanup — rip /api/message, ProactiveGreeter, ACPClient + install-bridge fixes#95
Open
BrettKinny wants to merge 6 commits into
Open
#16: ZeroClaw cleanup — rip /api/message, ProactiveGreeter, ACPClient + install-bridge fixes#95BrettKinny wants to merge 6 commits into
BrettKinny wants to merge 6 commits into
Conversation
…bearing The face-detected bare "Hi!" path previously suppressed only when at least one roster member had an `appearance:` field. Households where members were registered with just display_name + calendar prefix (the common configuration) still saw a bare greet stack on top of the room-view named greet, producing a double-greeting on each walk-in. Suppress when the registry has any members — accept silent-listen-mode for unidentified faces as the design (`Closes #23`, approach b). - HouseholdRegistry: add `__len__` (with the standard `_reload_if_changed` guard). - FaceGreeter: `_roster_has_appearances()` → `_roster_is_populated()`, checking `bool(self._household)`. - Tests: new non-empty case (display_name only fixture); existing appearance-bearing case preserved. Closes #23 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Iterating on .env config required a full bridge restart. Add a maintenance POST /admin/reload-config that re-reads a whitelist of env vars into the module globals in place, returning a diff of what changed. Scope is deliberately tight: vars whose only consumer is the request path (VISION_*, VLM_*, WEATHER_*, CALENDAR_TTL_SEC). Vars tied to background loops (CALENDAR_POLL_SEC, CALENDAR_IDS), file-watcher paths, LOCAL_TZ, or the voice-provider selector are excluded — those need a real restart. The route lives on the existing _admin_router (localhost-only via _admin_require_localhost), so no CSRF, no extra auth. Secrets are masked in the response: first4…last4, or *** for short values. Tests bypass the localhost guard via dependency_overrides and toggle bridge.csrf._ENFORCE (the documented kill-switch) since TestClient requests go through CSRFMiddleware. Closes #77 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The legacy ZeroClaw voice-server endpoints. Post-#36 voice traffic flows through PiVoiceLLM in xiaozhi-server; nothing in production hits these two routes. Per #16 they pay the ACP 24K-token tax for no signal and act as a misleading probe. - Drop both routes (305 + 190 LOC). - Drop the _dashboard_send_message wrapper and the send_message= wire-up through bridge/dashboard.py — never consumed by the dashboard. - Drop the route tests (MessageTests, MessageStreamTests). Baseline drops 7 tests; the rest of the suite is unaffected (255 passed). Refs #16. ACPClient + ProactiveGreeter + ZEROCLAW_* env vars follow in the next commits — this one removes the load-bearing consumers first so the dependency chain unwinds cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Layer 6 ProactiveGreeter was lifted into dotty-behaviour as the face_greeter consumer at #36. bridge.py's copy and its adapters (_PerceptionBusAdapter, _CalendarFacade, _greeter_llm_client, _greeter_tts_pusher) have been dead code ever since — instantiated in lifespan, never reached by any traffic. - Delete bridge/proactive_greeter.py (574 LOC) and its test file (453 LOC). - Remove the adapter section (~91 lines), the _proactive_greeter module global, the lifespan instantiate try-block, and the lifespan teardown if-block. - Rename the FastAPI title from "ZeroClaw Bridge" to "Dotty Admin Dashboard" — accurate post-#36. Tests drop from 255 to 234 (the 21 tests in test_proactive_greeter.py). All remaining tests pass. Refs #16. ACPClient + ZEROCLAW_* env vars follow in Phase B2 — now unblocked since this commit removes the last acp.prompt caller. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase A removed /api/message; Phase B removed ProactiveGreeter. Both
were the live consumers of ACPClient — class is now safely orphaned.
- Delete class ACPClient (~410 LOC) and the `acp = ACPClient()` global.
- Delete ZEROCLAW_BIN / REQUEST_TIMEOUT_SEC / SESSION_* env-var block
at the top of bridge.py — all tied to ACPClient lifecycle.
- Delete the now-dead voice-preparer helper cascade: _voice_preparer,
_wrap_voice, _wrap_voice_with_block, _build_speaker_block,
_build_perception_block, _resolve_speaker_for_request (175 LOC).
- Delete MessageIn / MessageOut / _SessionInvalid (~15 LOC).
- Drop acp.ensure_alive() startup + acp.shutdown() teardown from
lifespan.
- Collapse /health to {status, service} — the acp_running /
cached_session / session_turns fields are meaningless without acp.
- Update tests: remove _StubProc, _install_acp_stub, ZEROCLAW_BIN
setdefaults, and replace the 3-test HealthTests class with a single
shape-check.
bridge.py shrinks 5754 → 5127 (-627 LOC). All 232 remaining tests pass.
Refs #16. Model-swap path (ZEROCLAW_VOICE_CFG / _UNIT / DISCORD_* /
WORKSPACE env vars + _apply_model_swap) follows in Phase D — it's a
separate functional unit from ACPClient.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ment bridge.py no longer shells out to the zeroclaw binary post-#36, so the install script's --zeroclaw-bin requirement is a stale install-time gate that turns a fresh-clone install into a hard failure for any user who doesn't happen to have a Rust workspace lying around. - Drop --zeroclaw-bin flag, ZEROCLAW_BIN default, the existence-check block, and the systemd Environment= line for it. - Rename SERVICE_NAME zeroclaw-bridge → dotty-bridge. - Rename BRIDGE_DIR default /root/zeroclaw-bridge → /root/dotty-bridge. - Update Description= and the .env stub header to match. bash -n lints clean; grep -E 'zeroclaw|ZEROCLAW' on the file now returns zero matches. Refs #16. Closes the install-bridge.sh half of the #16 cleanup. The remaining model-swap rip (_apply_model_swap + admin routes + ZEROCLAW_VOICE_* env vars inside bridge.py) is deferred to a follow-up issue — that path was already marked "moot under pi-runtime decom" in #16's original Deferred section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR removes legacy ZeroClaw-era bridge functionality now that the voice path has moved elsewhere, while also updating the bridge installer/service naming and tightening up behaviour-side face-greeter logic to match the post-cutover architecture.
Changes:
- Remove
/api/message+/api/message/stream,ACPClient, and related voice-preparer/context-building plumbing frombridge.py. - Delete the bridge-side
ProactiveGreeter(and its tests) and align face-greeting behaviour with the behaviour-side consumer/household registry model. - Update
scripts/install-bridge.shto drop thezeroclawbinary requirement and rename the installed systemd service todotty-bridge; add an admin/admin/reload-configendpoint + tests.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
bridge.py |
Removes ZeroClaw ACP + message endpoints; simplifies /health; adds /admin/reload-config. |
bridge/dashboard.py |
Removes unused send_message wiring from dashboard configuration state. |
bridge/proactive_greeter.py |
Deletes the legacy bridge-side proactive greeter implementation. |
tests/test_proactive_greeter.py |
Deletes proactive greeter unit tests (feature removed). |
tests/test_bridge_routes.py |
Removes message/message-stream tests; updates /health assertions; adds /admin/reload-config tests. |
tests/test_dashboard_csrf.py |
Removes now-unneeded ZEROCLAW_BIN env setup. |
scripts/install-bridge.sh |
Renames install/service to dotty-bridge and drops --zeroclaw-bin requirement + unit env. |
dotty-behaviour/household/registry.py |
Adds __len__ to support truthiness/population checks. |
dotty-behaviour/consumers/face_greeter.py |
Changes face-detected suppression rule to “registry non-empty” (via truthiness) instead of “has appearances”. |
dotty-behaviour/tests/test_consumer_face_greeter.py |
Adds coverage for the updated face-detected suppression behaviour. |
Comments suppressed due to low confidence (1)
bridge.py:99
- The default kid-mode state path still points at
/root/zeroclaw-bridge/..., butscripts/install-bridge.shnow installs into/root/dotty-bridgeand the service is renamed todotty-bridge. This leaves state/log files split across legacy and new directories and undermines the “zeroclaw cleanup” intent. Consider updating the default paths (kid/smart/convo logs) to adotty-bridgelocation or setting these via the generated systemd unit’s EnvironmentFile so installs are self-consistent.
_KID_STATE_FILE = Path(
os.environ.get("DOTTY_KID_MODE_STATE", "/root/zeroclaw-bridge/state/kid-mode")
)
# Voice-daemon LLM is selected by `smart_mode` only. kid_mode is orthogonal —
# guardrails (content sandwich, denied tools, persona) are independent of the
# model. smart_mode OFF → DEFAULT_MODEL. smart_mode ON → SMART_MODEL.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -635,7 +628,6 @@ def _tier1slim_target_for_smart_mode(enabled: bool) -> tuple[str, str, str]: | |||
| logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") | |||
| log = logging.getLogger("zeroclaw-bridge") | |||
Comment on lines
+4805
to
+4809
| raw = os.environ.get(env_name, "") | ||
| try: | ||
| new = caster(raw) if raw != "" else ( | ||
| "" if caster is str else caster(0) | ||
| ) |
Comment on lines
32
to
33
| # Bridge wires its in-process message handler in via configure(). Lets the | ||
| # "Say" action invoke the same path /api/message uses without an HTTP hop. |
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.
Summary
Closes the load-bearing post-#36 dead code from the ZeroClaw retirement in four staged commits. Net: ~2,228 LOC removed, bridge.py shrinks from 6,151 → 5,127 (-17%), full test suite stays green.
Phase A —
/api/message+/api/message/streamroutesPer #16, these legacy ZeroClaw voice-server endpoints were "unused by real voice traffic" — voice now flows through
PiVoiceLLMin xiaozhi-server. Also drops the_dashboard_send_messagewrapper and its dead wire-up intobridge/dashboard.py(send_message=...was set but never consumed by the dashboard module). -398 LOC.Phase B —
ProactiveGreeter(Layer 6) ripbridge/proactive_greeter.pyand its test were lifted intodotty-behaviour/consumers/face_greeter.pyat #36 cutover. Deletes both files plus the adapter section + lifespan instantiate/teardown blocks in bridge.py. Also renames FastAPI app title from"ZeroClaw Bridge"→"Dotty Admin Dashboard". -1,150 LOC.Phase B2 —
ACPClient+ voice-preparer cascadeWith Phases A + B removing all
acp.prompt()callers, the 410-LOCACPClientclass is safely orphaned. Also drops the now-dead voice-preparer helper cascade (_voice_preparer,_wrap_voice,_wrap_voice_with_block,_build_perception_block,_build_speaker_block,_resolve_speaker_for_request),MessageIn/MessageOut, theZEROCLAW_BIN/ session-timeout env-var block, andacp.shutdown()/acp.ensure_alive()in lifespan./healthcollapses to a shape-check. -670 LOC across bridge.py + tests.Phase D —
scripts/install-bridge.shThe bridge no longer needs the zeroclaw binary, so the script's
--zeroclaw-binrequirement was a stale install-time gate that hard-failed for any fresh-clone user without a Rust workspace. Drops the flag, the existence-check, theEnvironment=ZEROCLAW_BIN=...from the systemd unit; renames servicezeroclaw-bridge→dotty-bridge.grep -E 'zeroclaw|ZEROCLAW'now returns zero matches in the file.Deferred (separate follow-up)
The model-swap path inside
bridge.py—_apply_model_swap,_admin_modelroute,_admin_safetyroute's restart trigger,ZEROCLAW_VOICE_*/ZEROCLAW_DISCORD_*/ZEROCLAW_WORKSPACEenv vars,DOTTY_VOICE_PROVIDER="zeroclaw"default — is tangled with the still-live_admin_safetyMCP-allowlist editor and the not-yet-implemented PiVoiceLLM smart-mode model swap. #16's original Deferred section already flagged this area as "moot under pi-runtime decom" so it's the natural follow-up.Test plan
python3 -m py_compile bridge.py— clean.venv/bin/pytest tests/ -q— 232 passed, 0 failed (was 262 pre-cleanup; the 30-test delta is the deletedtest_proactive_greeter.py(21) +MessageTests+MessageStreamTests(7) + 3→1HealthTestscollapse (2), all expected)bash -n scripts/install-bridge.sh— cleanacp.*,ACPClient,ZEROCLAW_BIN, orclass ACPClientreferences in bridge.pyCloses #16
🤖 Generated with Claude Code