Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
269a9f1
fix post-release automation findings
BrettKinny Jul 12, 2026
fc960b6
fix firmware onboarding and release docs
BrettKinny Jul 16, 2026
2626077
fix: serialize PiVoice RPC turns
0Downtime Aug 11, 2026
d9ceb71
fix(test): preserve continuous microphone evidence in bounded AV sess…
BrettKinny Sep 12, 2026
780cf03
test(av): measure acoustic quality and clarify live feature contracts
BrettKinny Sep 12, 2026
b3123b7
test(av): verify quiet replies and separate cold wake from warm follo…
BrettKinny Sep 12, 2026
bb04055
fix: keep ambient sound turns out of active conversations
BrettKinny Sep 12, 2026
391fbca
test(av): treat missing quiet-speech transcripts as inconclusive
BrettKinny Sep 12, 2026
e670613
test: exercise all voice tools with isolated synthetic memory
BrettKinny Sep 12, 2026
dfd72b8
test(av): bind pre-rendered prompts to exact text and waveform hashes
BrettKinny Sep 12, 2026
41080f2
test: make response VAD experiments explicit and reproducible
BrettKinny Sep 12, 2026
0344837
fix: unwrap ASR content before correction and routing
BrettKinny Sep 12, 2026
6381f46
docs: align sleep acceptance with firmware privacy contract
BrettKinny Sep 12, 2026
9493575
fix: preserve ASR intent instead of fuzzy-matching commands
BrettKinny Sep 12, 2026
1f3e9da
fix(voice): reject explicit negated and quoted state commands
BrettKinny Sep 12, 2026
74a6cfa
fix: guard voice camera access with live child policy
BrettKinny Sep 12, 2026
3f46836
test: require an explicit overnight deployment host
BrettKinny Sep 12, 2026
2a51e06
test(av): capture optional float PCM and require explicit listening r…
BrettKinny Sep 12, 2026
a0c2657
test(av): report native-channel prompt and response quality separately
BrettKinny Sep 12, 2026
50c68e2
test(av): require fresh listening status before warm capture
BrettKinny Sep 13, 2026
258b9e2
wip: pre-migration snapshot (CachyOS reinstall prep)
BrettKinny Sep 17, 2026
da4a6d3
fix(voice): clear abort flag when a new user turn is accepted
BrettKinny Oct 5, 2026
f0e6cda
fix(asr): drop WhisperLocal transcripts with a high no-speech score
BrettKinny Oct 5, 2026
f8f200a
chore(pi_voice): sync provider with the code deployed from PR #173
BrettKinny Oct 5, 2026
bcfc225
fix(pi_voice): give pi a Dotty system prompt on the live voice path
BrettKinny Oct 5, 2026
baf85d7
test(av): let the overnight runner open the mic and stop scoring eval…
BrettKinny Oct 5, 2026
1892510
fix(dashboard): relay perception feed, drop dead waits, disable sound…
BrettKinny Oct 5, 2026
bfe69b6
fix(persona): tell the voice persona to answer briefly and stop
BrettKinny Oct 5, 2026
2114148
feat(dashboard): report voice turns and filter hits from PiVoiceLLM
BrettKinny Oct 5, 2026
d42b146
test(av): set aside cases the evidence cannot settle; a misheard prom…
BrettKinny Oct 5, 2026
e6badc3
feat(av): portrait crop option for clip exports
BrettKinny Oct 5, 2026
94530f1
Merge branch 'pr-173' into release/server-v0.2.0-rc.1
BrettKinny Oct 5, 2026
fda3b5d
Merge branch 'pr-175' into release/server-v0.2.0-rc.1
BrettKinny Oct 5, 2026
92fc7af
Merge branch 'pr-184' into release/server-v0.2.0-rc.1
BrettKinny Oct 5, 2026
b6dc2ba
docs(modes): reword historical-pin note so the onboarding doc check p…
BrettKinny Oct 5, 2026
ec04a31
chore(av): drop unused import flagged by ruff
BrettKinny Oct 5, 2026
8356a90
Merge test/overnight-av-20260912 (bfe69b6) into web-dashboard-fixes
BrettKinny Oct 5, 2026
d3a320e
docs(changelog): record the voice fixes and runner changes going into…
BrettKinny Oct 5, 2026
08b1f69
Merge remote-tracking branch 'origin/web-dashboard-fixes' into releas…
BrettKinny Oct 5, 2026
11eb4d5
fix(memory): keep prompt scaffolding out of memory and stop speaking …
BrettKinny Oct 5, 2026
39975e4
docs(changelog): record the memory scaffolding fix (#186)
BrettKinny Oct 5, 2026
7844b30
fix(think_hard): outlast the reasoner's cold load and speak before wa…
BrettKinny Oct 5, 2026
72bbd7c
feat(behaviour): opt-in DOTTY_LOCAL_ONLY guard for outbound routes
BrettKinny Oct 13, 2026
821c346
Merge pull request #188 from BrettKinny/feat/local-only-guard
BrettKinny Oct 13, 2026
a9b7359
fix(behaviour): make GET /api/vision/latest non-destructive
BrettKinny Oct 19, 2026
be206ca
fix(kid-mode): fail-closed filter with an imitable-danger tier
BrettKinny Oct 19, 2026
3f4c165
fix(behaviour): expire test probe devices from per-device perception …
BrettKinny Oct 19, 2026
cb5585d
fix(dashboard): judge only the live robot for State and sensor staleness
BrettKinny Oct 19, 2026
cdce1df
fix(xiaozhi-admin): end the listening session on admin idle/sleep
BrettKinny Oct 19, 2026
f9f3e7e
fix(voice): enforce one supported leading face on every voice path
BrettKinny Oct 19, 2026
73f119b
fix(kid-mode): steer replies to the actual ask and away from imitable…
BrettKinny Oct 19, 2026
e75d36c
fix(xiaozhi): restore the device's sticky state on WebSocket reconnec…
BrettKinny Oct 19, 2026
80fae86
fix(dashboard): keep the Kid Mode card on the persisted guardian policy
BrettKinny Oct 19, 2026
ae66f23
docs: describe the shared face guard, danger tier and kid rules 10-12
BrettKinny Oct 19, 2026
17149b5
fix(bridge): resync the robot's toggle pips on bridge startup
BrettKinny Oct 19, 2026
32231f1
Merge agent/output-safety: face guard, kid-mode filter fail-closed, d…
BrettKinny Oct 19, 2026
1e6a01b
fix(tts): keep server-push audio past sendAudioMessage's stale check …
BrettKinny Oct 19, 2026
008e15a
feat(dashboard): replay recent turns on /ui/events and resume on reco…
BrettKinny Oct 19, 2026
7d05ec3
fix(pi_voice): voice-only tool set, no auto-compaction, take_photo ru…
BrettKinny Oct 19, 2026
4797d02
fix(pi_voice): route explicit tool requests reliably, past xiaozhi's …
BrettKinny Oct 19, 2026
a1f2766
fix(dotty-pi-ext): keep camera and room views out of memory; stop hed…
BrettKinny Oct 19, 2026
0fb1968
fix(dotty-pi): set XIAOZHI_HOST so play_song can reach xiaozhi-server
BrettKinny Oct 19, 2026
2d9a04e
fix(asr): bias Whisper toward the wake-name; correct real-name mishea…
BrettKinny Oct 19, 2026
28214bb
fix(songs): list and play the MIDI songs, not just purr.opus
BrettKinny Oct 19, 2026
d2bdbb1
test(av): add non-acoustic integration check and Piper prompt renderer
BrettKinny Oct 19, 2026
8a733fa
fix(voice): end the session after a storm of interrupted replies (#105)
BrettKinny Oct 19, 2026
0c7242d
Merge agent/voice-tools: tool routing, ROOM_VIEW prefix, pi builtin t…
BrettKinny Oct 19, 2026
627b6ba
Merge agent/voice-session: admin end-session, sticky state on reconne…
BrettKinny Oct 19, 2026
cf183ee
feat(scripts): add read-only dashboard smoke checker
BrettKinny Oct 19, 2026
7aa3c03
Merge agent/dashboard: live state/kid cards, probe expiry, non-destru…
BrettKinny Oct 19, 2026
e0a2697
test(av): add seven pi-tool cases that prove the tool ran
BrettKinny Oct 19, 2026
c1189d7
test(av): run state cases unattended with a verified dashboard escape
BrettKinny Oct 19, 2026
4e5aedb
docs(av): document the release coverage run and case contracts
BrettKinny Oct 19, 2026
379a992
test(av): probe the brain.db evidence reader in preflight
BrettKinny Oct 19, 2026
a82a8da
Merge agent/av-coverage: tool, state and cold-wake A/V cases, integra…
BrettKinny Oct 19, 2026
ed165f3
fix(dashboard): stop the perception feed relay freezing the bridge on…
BrettKinny Oct 19, 2026
6eae802
fix(scripts): close smoke-check streams deterministically and flag ol…
BrettKinny Oct 19, 2026
29b422a
Merge agent/dashboard follow-up: unblock bridge on feed disconnect, s…
BrettKinny Oct 19, 2026
84f3bac
fix(openai_compat): follow the live kid-mode toggle per turn
BrettKinny Oct 20, 2026
39294a0
test(pi_voice): pin the output guard on the direct think_hard route
BrettKinny Oct 20, 2026
998cc37
docs(setup): name the SoftAP portal's Advanced tab correctly
BrettKinny Oct 20, 2026
87b116c
Merge agent/issue-sweep: name the SoftAP portal's Advanced tab (#172)
BrettKinny Oct 20, 2026
adbc2c5
fix(play_song): start the song after the turn's reply instead of losi…
BrettKinny Oct 20, 2026
9cb515b
fix(behaviour): keep wake-word head turns out of dance and security
BrettKinny Oct 20, 2026
215ed7d
docs(readme): cut the status note to a short, current statement
BrettKinny Oct 20, 2026
7726c21
Merge agent/loose-ends: live kid mode in OpenAICompat, play_song afte…
BrettKinny Oct 20, 2026
3416392
docs(readme): plainer wording for the why and AI-transparency paragraphs
BrettKinny Oct 20, 2026
88ad8f5
docs(changelog): record the fixes integrated for server-v0.2.0-rc.1
BrettKinny Oct 20, 2026
ea3b368
docs(readme): correct stale claims and drop em dashes throughout
BrettKinny Oct 20, 2026
a62251a
fix(behaviour): greet faces only in idle and talk
BrettKinny Oct 20, 2026
ad7fde5
fix(behaviour): purr on head pets only in idle and talk
BrettKinny Oct 20, 2026
9955cd4
fix(behaviour): abort on face_lost only in idle and talk
BrettKinny Oct 20, 2026
d6b704f
Merge agent/consumer-gates: greeter, purr and face-lost abort act onl…
BrettKinny Oct 20, 2026
12526cb
test(av): add kid-mode cases for #178 and the #157 output filter
BrettKinny Oct 20, 2026
1b813a4
fix(docker): put the pip CUDA libs on LD_LIBRARY_PATH for WhisperLocal
BrettKinny Oct 20, 2026
9d90dc6
fix(asr): hold a lone hotword transcript to a stricter no-speech score
BrettKinny Oct 20, 2026
ecd80cf
test(av): accept inflected gravity words in V05
BrettKinny Oct 20, 2026
27b0ec4
fix(memory): fall back to keyword overlap when the recall phrase misses
BrettKinny Oct 20, 2026
68c8f06
fix(pi_voice): forward PiClient's stdlib log records to the provider log
BrettKinny Oct 20, 2026
3a92fb9
test(av): accept "mooncrackers" as one word in T04 and T03
BrettKinny Oct 20, 2026
28a8b43
fix(pi_voice): route "use your camera" to take_photo; readable log lines
BrettKinny Oct 20, 2026
82a5f5c
test(av): count a successful direct tool route as the expected tool
BrettKinny Oct 20, 2026
f6bc961
test(av): retry a stale listening status instead of blocking the case
BrettKinny Oct 20, 2026
2379aa1
test(av): retry an empty VAD response transcript without VAD
BrettKinny Oct 20, 2026
4f4cc75
test(av): swap 'Brisbane' for 'banana' in V02
BrettKinny Oct 20, 2026
993bf61
fix(pi_voice): drop a post-tool turn that only repeats the pre-tool line
BrettKinny Oct 20, 2026
40b8811
build(docker): pin the xiaozhi image's pip packages
BrettKinny Oct 20, 2026
1cbdb55
test(integration): fail when WhisperLocal's warm-up transcription fails
BrettKinny Oct 20, 2026
122de9c
fix(pi_voice): put the voice rules in pi's system prompt, not every turn
BrettKinny Oct 20, 2026
acf91c3
Merge agent/tool-rules-in-system-prompt: voice rules in pi's system p…
BrettKinny Oct 20, 2026
45a0449
fix(asr): keep 1.2 s of pre-roll before the VAD fires
BrettKinny Oct 20, 2026
918e4f6
test(av): accept Whisper's mishearings of 'Dotty' in V01's reply
BrettKinny Oct 20, 2026
a84ee5b
fix(kid-mode): repeating ordinary words is not a jailbreak
BrettKinny Oct 20, 2026
50e2dba
test(av): start the reply crop nearer the reply, by the measured capt…
BrettKinny Oct 20, 2026
d76a17c
test(av): bias the reference transcript toward 'Dotty'
BrettKinny Oct 20, 2026
84ea334
test(av): retry without VAD when the VAD transcript lacks the reply w…
BrettKinny Oct 20, 2026
79ad6c9
test(av): drop unsure segments from the no-VAD reply transcript
BrettKinny Oct 20, 2026
a9d6040
fix(kid-mode): drop 'spell' from the repeat-words rule
BrettKinny Oct 20, 2026
91f516c
fix(pi_voice): cap tool calls per reply; think_hard for hard question…
BrettKinny Oct 20, 2026
393c14b
test(av): a disconnected robot pauses the run instead of failing the …
BrettKinny Oct 21, 2026
f43980e
docs: build the firmware from source in the quickstart, not the LAN-l…
BrettKinny Oct 21, 2026
291e527
ci: stop auto-publishing LAN-locked firmware binaries on fw-v* tags
BrettKinny Oct 21, 2026
1e3860e
docs(changelog): all three fw releases are now source-only
BrettKinny Oct 21, 2026
061fe12
chore: drop a pi session export, audit drafts and a test artifact fro…
BrettKinny Oct 21, 2026
7218a3c
test(docs): guard the build-from-source quickstart, not the fw-v1.3.3…
BrettKinny Oct 21, 2026
9ab676b
fix(kid-mode): danger tier blocks invitations to copy, not facts
BrettKinny Oct 21, 2026
54d23b3
fix(kid-mode): retell think_hard answers through the 4B under the rules
BrettKinny Oct 21, 2026
ee77653
fix(pi_voice): restart pi when an aborted tool loop does not end
BrettKinny Oct 21, 2026
32cb6bc
fix(voice): count only spoken interruptions toward the barge-in close
BrettKinny Oct 21, 2026
9cfc553
fix(persona): point at the rules in the system prompt, not 'the end o…
BrettKinny Oct 21, 2026
b8a5690
fix(behaviour): restore saved state per device and never fail startup…
BrettKinny Oct 21, 2026
ffef038
fix(kid-mode): vision prompts and greetings follow the shared Kid Mod…
BrettKinny Oct 21, 2026
4f1ecd5
fix(compose): let the bridge state mount follow a relocated state dir
BrettKinny Oct 21, 2026
14b3aff
fix(dashboard): ignore probe devices for last-seen; cache the devices…
BrettKinny Oct 21, 2026
d2a7bdb
chore: replace the maintainer's LAN address and robot MAC with placeh…
BrettKinny Oct 21, 2026
67c91ff
docs: match the docs to the release; drop the maintainer's host and MAC
BrettKinny Oct 21, 2026
e960351
test(av): close false passes and unsafe paths found in the harness re…
BrettKinny Oct 21, 2026
cf5243d
fix(admin): let /xiaozhi/admin/say speak after an abort
BrettKinny Oct 22, 2026
69d57a2
test(av): use a plain name for the person-memory cases
BrettKinny Oct 22, 2026
e5b0726
test(av): score V07 on its answer, not on calling think_hard
BrettKinny Oct 22, 2026
f6a0000
docs(changelog): note the admin/say-after-abort fix
BrettKinny Oct 22, 2026
25dcb7c
fix(pi_voice): look memory up afresh when asked again
BrettKinny Oct 23, 2026
68a834d
fix(pi_voice): run recall_person directly for "what do you know about…
BrettKinny Oct 23, 2026
be2d16a
fix(pi_voice): play a named song directly instead of letting the 4B d…
BrettKinny Oct 23, 2026
53d8cd5
fix(kid-mode): ask again when a stray word shows a mishearing
BrettKinny Oct 23, 2026
1362c78
Revert "fix(kid-mode): ask again when a stray word shows a mishearing"
BrettKinny Oct 23, 2026
b44acd8
test(av): let a speech-optional case pass with music and no TTS turn
BrettKinny Oct 23, 2026
3da29be
docs(changelog): note the recall_person and play_song direct routes
BrettKinny Oct 23, 2026
38383ab
test(av): pause after the wake word in W01's prompt
BrettKinny Oct 23, 2026
9805c37
test(av): give Dotty's wake greeting 8 s before W01's question
BrettKinny Oct 23, 2026
072cd22
test(av): let the robot settle after going cold before a wake word
BrettKinny Oct 23, 2026
f11e1ae
test(av): 12 s for Dotty's wake greeting before W01's question
BrettKinny Oct 23, 2026
f7630b3
fix(xiaozhi-admin): keep a sleeping robot reachable so the dashboard …
BrettKinny Oct 23, 2026
d80b5e1
fix(xiaozhi): import the TTS provider at startup so a fast reconnect …
BrettKinny Oct 23, 2026
b370705
test(av): no "Dotty" name bias when transcribing a silence case
BrettKinny Oct 23, 2026
5651a59
chore(release): server-v0.2.0-rc.1
BrettKinny Oct 23, 2026
b30c008
test(av): stub device tools in the existing-sidecar guard test
BrettKinny Oct 27, 2026
2a6aac4
test(overnight): stub the disk-space guard in runner tests
BrettKinny Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .config.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ ASR:
# Optional decoder bias — short list of canonical phrases improves
# recall on rare names. Keep under ~200 chars to avoid prompt bleed.
initial_prompt: null
# Bias the decoder toward the wake-name so it stops coming back as
# Jody / Donny / Duddy (#164). null disables. Needs faster-whisper >= 1.0
# (ignored with a warning on older builds).
hotwords: <ROBOT_NAME>
SenseVoiceOnnx:
# int8 sherpa-onnx SenseVoiceSmall — no PyTorch, lighter for Pi-class hosts
# (#135). Opt-in: set selected_module.ASR: SenseVoiceOnnx to use it.
Expand Down
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ PORT=8081
# Same key as above works if your provider supports vision models.
# VISION_API_KEY=sk-or-v1-...

# Keep camera frames and room audio on the LAN (dotty-behaviour). When set,
# any VLM / audio-caption / narrative URL that is not loopback or a private
# address is disabled at startup instead of falling back to the cloud
# default, and weather + calendar fetches are switched off. Point the VLM at
# a local OpenAI-compatible vision model to keep the camera working:
# DOTTY_LOCAL_ONLY=1
# VLM_API_URL=http://127.0.0.1:8080/v1/chat/completions
# VLM_MODEL=<your-local-vision-model>
# VLM_API_KEY=local # any non-empty value; local servers ignore it

# --- Google Calendar integration (optional) ---

# Comma-separated Google Calendar IDs for context injection.
Expand Down
12 changes: 8 additions & 4 deletions .github/workflows/firmware-release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Build StackChan firmware and publish a GitHub Release.
#
# Triggered by tags matching fw-v* (e.g. fw-v1.0.0).
# Manual only (2026-10-21): the firmware's server address is compiled in
# (CONFIG_OTA_URL), so these binaries only work on the network they were
# built for. Nothing here stops that: a manual run publishes whatever
# CONFIG_OTA_URL the pinned source has, so don't run it until #190 makes a
# prebuilt that can be pointed at any server, then restore the fw-v* tag
# trigger. A manual run names the release after the ref it runs on, so run
# it from a tag.
# Uses the Espressif IDF Docker container to build the ESP32-S3 firmware,
# then attaches the binaries + SHA256 checksums to a GitHub Release.
#
Expand All @@ -11,9 +17,7 @@
name: Firmware Release

on:
push:
tags:
- 'fw-v*'
workflow_dispatch:

permissions:
contents: write
Expand Down
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ sbom-server.json
htmlcov/
.pytest_cache/

# Local UAT evidence. Keep compact manifests/results/draft issue summaries
# visible for selective review, but never offer raw household media, event
# streams, health snapshots, or container logs for an accidental commit.
/uat-sessions/**/video/
/uat-sessions/**/clips/
/uat-sessions/**/logs/
/uat-sessions/**/ndjson/
/uat-sessions/**/snapshots/

# Generated audit/session outputs. These can contain machine-local paths,
# prompts, or deployment observations; regenerate or curate before publishing.
/AUDIT-REPORT.md
/audit-draft-issues.md
/pi-session-*.html
# Session-id file a test writes when a DB path is ":memory:".
*.ses

# Frontend build deps for the dashboard's vendored Tailwind bundle.
# package.json + tailwind.config.js are committed; build artifacts and
# the npm install state are not. Re-run `npm install && npm run build:css`
Expand Down
54 changes: 54 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The voice path runs through a single LLM provider — `PiVoiceLLM`, selected via

```
StackChan hardware → configured persona
│ ESP32-S3, xiaozhi firmware (built from m5stack/StackChan source)
│ ESP32-S3, xiaozhi firmware (pinned BrettKinny/StackChan@dotty fork)
│ WiFi / WebSocket (Xiaozhi protocol)
▼
xiaozhi-esp32-server (Docker)
Expand Down Expand Up @@ -197,7 +197,8 @@ For hardware specs, protocol details, model internals, latent capabilities, and

- xiaozhi-esp32-server: https://github.com/xinnan-tech/xiaozhi-esp32-server
- xiaozhi-esp32 firmware (upstream): https://github.com/78/xiaozhi-esp32
- StackChan (hardware + firmware patches): https://github.com/m5stack/StackChan
- StackChan upstream (hardware + base firmware): https://github.com/m5stack/StackChan
- Dotty firmware fork (the pinned build source): https://github.com/BrettKinny/StackChan/tree/dotty
- Emotion protocol: https://xiaozhi.dev/en/docs/development/emotion/

## Agent skills
Expand Down
44 changes: 27 additions & 17 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ For protocol wire formats see `docs/protocols.md`.

| Component | Current Version | Protocol / Interface | Breaking Change Policy |
|---|---|---|---|
| StackChan firmware (m5stack/StackChan v1.2.4) | v1.2.4 | Xiaozhi WebSocket protocol, MCP over WS (JSON-RPC 2.0) | Pin firmware to a known-good build; do not OTA-update without verifying server compatibility first |
| StackChan firmware (`BrettKinny/StackChan@dotty`) | `fw-v1.3.3` release; submodule `969c2b2` | Xiaozhi WebSocket protocol, MCP over WS (JSON-RPC 2.0), StateManager event contract | Build the pinned submodule; do not substitute the official upstream tree or OTA-update without coordinated verification |
| xiaozhi-esp32-server (local build) | `xiaozhi-esp32-server-piper:local` | Custom LLM provider API, `.config.yaml` schema, Xiaozhi WS server | Rebuild image only after checking upstream changelog for provider API or config schema changes |
| dotty-pi (pi agent) | `dotty-pi:0.1.0` | pi RPC (JSONL over stdio), the five `dotty-pi-ext` voice tools | Pin the image tag; pi-version or model changes need end-to-end cutover testing |
| dotty-pi (pi agent) | `dotty-pi:0.1.0` | pi RPC (JSONL over stdio), the seven `dotty-pi-ext` voice tools | Pin the image tag; pi-version or model changes need end-to-end cutover testing |
| dotty-behaviour | `dotty-behaviour:0.1.0` | HTTP API (`/api/perception/*`, `/api/vision/*`, `/api/audio/*`, `/health`) | Endpoint signatures stable; perception event-schema changes require firmware + xiaozhi review |
| bridge.py (dashboard) | unversioned (HEAD) | `/ui` dashboard, `/admin/*`, `/health` | Dashboard/admin service only post-#36; admin route changes require updating dashboard callers |
| bridge.py (dashboard) | `dotty-bridge:0.1.0` image from repo HEAD | `/ui` dashboard, `/admin/*`, `/health` | Dashboard/admin service only post-#36; admin route changes require updating dashboard callers |

The public `fw-v1.3.3` superproject tag (commit `24a009c`, 2026-07-12) is the
current coordinated release pointer. It pins firmware submodule `969c2b2` and
the matching server-side patches. Draft PRs and a dirty submodule are not a
released compatibility set.

## What counts as a breaking change

Expand All @@ -42,27 +47,28 @@ Any of the following require coordinated updates across components:

## Versioning strategy

No formal versioning is adopted yet (tracked in
[ROADMAP.md](ROADMAP.md#community-wishlist) under "Firmware/server
compatibility matrix"). When adopted, the plan is:
The repo uses separate tag namespaces:

- `server-vX.Y.Z` for server-only release milestones.
- `fw-vX.Y.Z` for coordinated firmware release pointers in this superproject.

- Separate tag namespaces: `server-vX.Y.Z` and `fw-vX.Y.Z`.
- This matrix will document which server versions are compatible with which
firmware versions.
- The bridge will carry its own version once it moves to a tagged release
cadence.
Container image tags remain `0.1.0` today and are not sufficient by themselves
to identify the exact source revision; retain the Git commit/tag alongside a
deployment record.

## Upgrade guidance

1. **Check this matrix first.** Confirm the component you are upgrading is
compatible with the versions of the other components you are running.
2. **Back up before upgrading.** Run `scripts/backup.sh` (or the equivalent
manual steps) to snapshot config, persona files, and bridge state.
2. **Back up before upgrading.** Manually snapshot `.env`, rendered
`data/.config.yaml`, persona/household files, `brain.db` (including WAL/SHM
companions), and the bridge state directory. This repo does not currently
ship an automated backup script.
3. **Upgrade one component at a time.** Validate with a health check
(`curl http://<XIAOZHI_HOST>:8090/health` and `:8081/health`) plus a live
voice turn before moving to the next component.
4. **Tail logs during validation.** Watch both the xiaozhi-server container
logs and the bridge journal simultaneously to catch mismatches early.
4. **Tail logs during validation.** Watch the xiaozhi-server, dotty-pi,
dotty-behaviour, and bridge container logs together to catch mismatches.
5. **Roll back if broken.** Restore from the backup taken in step 2 and
revert to the previous image or binary.

Expand Down Expand Up @@ -96,7 +102,11 @@ Server and firmware are versioned independently:
The docs live as plain markdown under `docs/` and render on GitHub directly —
there is no separate docs-site build to deploy.

GitHub Actions handles image builds and artifact publishing from the tag.
Pushing a tag does not trigger any build or publish. The firmware release
workflow (`firmware-release.yml`) is manual-only, and no firmware binaries are
published at the moment, because the server address is compiled in; a
portable prebuilt is tracked in
[#190](https://github.com/BrettKinny/dotty-stackchan/issues/190).

### Compatibility matrix updates

Expand All @@ -106,4 +116,4 @@ versions work with which firmware versions.

---

Last verified: 2026-05-22.
Last verified against the repository and `fw-v1.3.3` pin: 2026-07-16.
23 changes: 22 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
# Pinned 2026-05-17 from :server_0.9.3
FROM ghcr.io/xinnan-tech/xiaozhi-esp32-server@sha256:3accd82a7d1a6c01c58f32f6199400a11655d607780b80219493123dedbb347e

RUN pip install --no-cache-dir piper-tts scipy numpy mido faster-whisper sherpa-onnx==1.13.2
# Versions pinned to the image that passed the 2026-10-20 A/V run; an unpinned
# rebuild could otherwise change the Whisper stack underneath WhisperLocal.
RUN pip install --no-cache-dir piper-tts==1.8.0 scipy==1.15.3 numpy==1.26.4 mido==1.3.3 \
faster-whisper==1.2.1 ctranslate2==4.8.3 sherpa-onnx==1.13.2

# CTranslate2 (faster-whisper) dlopens libcublas.so.12 and cuDNN by name and
# doesn't look inside the pip CUDA wheels, so WhisperLocal on device=cuda fails
# every utterance with "libcublas.so.12 is not found" without this.
ENV LD_LIBRARY_PATH=/usr/local/lib/python3.10/site-packages/nvidia/cublas/lib:/usr/local/lib/python3.10/site-packages/nvidia/cudnn/lib

# Patch upstream TTS consumers and the audio sender to treat explicitly
# registered server-push sentence IDs as independent from chat-turn
# stale-message arbitration (#104).
COPY scripts/patch-tts-server-push.py /tmp/patch-tts-server-push.py
RUN python /tmp/patch-tts-server-push.py \
/opt/xiaozhi-esp32-server/core/providers/tts \
/opt/xiaozhi-esp32-server/core/handle/sendAudioHandle.py

# Keep ~1.2 s of audio from before the VAD fires (upstream ~0.6 s), so a soft
# first word still reaches ASR.
COPY scripts/patch-asr-preroll.py /tmp/patch-asr-preroll.py
RUN python /tmp/patch-asr-preroll.py /opt/xiaozhi-esp32-server/core/providers/asr/base.py

# fluidsynth + General MIDI soundfont for runtime rendering of dance/song MIDI
# files to Opus. Installed as the LAST layer so iteration on Python deps above
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ setup: _preflight-compose ## Interactive first-run wizard (re-runnable; remember
echo -e "$(GREEN)$(BOLD)Setup complete.$(RESET)"; \
echo ""; \
echo "Next steps:"; \
echo " 1. Flash the StackChan firmware (see SETUP.md or m5stack/StackChan repo)."; \
echo " 2. In the device's Advanced Options, set the OTA URL to:"; \
echo " http://$$XIAOZHI_HOST:8003/xiaozhi/ota/"; \
echo " 1. Build and flash StackChan firmware with this compiled setting:"; \
echo " CONFIG_OTA_URL=\"http://$$XIAOZHI_HOST:8003/xiaozhi/ota/\""; \
echo " See SETUP.md. The on-device Settings app has no OTA URL editor."; \
echo " 2. Provision the robot's 2.4 GHz Wi-Fi using its displayed setup flow."; \
echo " 3. Run 'make doctor' to verify everything is healthy."; \
echo ""

Expand Down
Loading
Loading