Behavior flags
STACKCHAN.RON’s behavior: block gathers the firmware’s opt-in
surfaces: visual overlays, motor-saver timing, sidecar URLs,
wake-word knobs. The block is optional — leave it out entirely and
every flag falls back to the defaults below, all chosen so a stock
device boots into a quiet desk-toy posture (no chimes, no toasts,
no battery icon, no agent, motors held).
The source of truth is BehaviorConfig
in stackchan-net. New fields land there with their own doc comment;
this page is a thin operator reference, kept in sync via PR review
rather than as a separate process. When a field’s behavior is rich
enough to warrant its own page (e.g. audio debug, sidecar), the
Notes column links to it.
Reference
| Field | Type | Default | Reboot? | Notes |
|---|---|---|---|---|
soliloquy_enabled |
bool | false |
live | Writes random soliloquy lines into face.bubble. Bubble TTL is fixed; no audio playback in this iteration. |
hourly_chime_enabled |
bool | false |
live | Plays a short chirp at the top of every wall-clock hour. Waits for SNTP sync before scheduling. |
battery_icon_enabled |
bool | false |
live | Small battery glyph top-left of the face. Quantised at the source so a 1 % change does not redraw. |
toast_overlay_enabled |
bool | false |
live | Bottom-of-screen toast band for warn / error events (POST /toast, crate::toast::push, MCP push_toast). 3 s TTL. |
auto_torque_release_ms |
u32 | 0 |
live | Idle window after which SCServo holding torque releases. 0 keeps torque on continuously (v0.1.0 behavior). Useful for units that sit idle for hours. |
audio_debug_udp_target |
"host:port" |
empty | live | UDP tee of the microphone stream. Bench-only — see audio-debug. |
agent_sidecar_url |
URL | empty | live | HTTP target for push-to-talk audio. Empty disables the agent task. See sidecar for the wire protocol and voice for the end-to-end loop. |
agent_sidecar_token |
string | empty | live | Bearer token for the sidecar. Wire-redacted in GET /settings exactly like wifi.psk and auth.token. |
follower_leader_hostname |
string | empty | live | Bare first label of another Stack-chan to mimic via mDNS (e.g. "kitchen-cat", not "kitchen-cat.local"). Empty disables follower mode. |
wake_word_enabled |
bool | false |
reboot | Runs on-device wake-word detection. Loads /sd/WAKE_WORD.tflite at boot; missing file parks the task. |
wake_word_threshold |
i8 | 100 |
reboot | Int8 detection cut-point. Bundled-model reference ≈ 0.95 confidence lands near 100. Lower = more sensitive. |
wake_word_arena_kib |
u32 | 64 |
reboot | TFLite Micro arena size in KiB. Allocated once at boot from PSRAM. Must be >= 1; 0 is rejected by validation. |
persona_name |
string | empty | live | Persona slug advertised to the sidecar via X-Persona-Name. Empty leaves the header off (sidecar default persona). ≤ 64 bytes, no control chars / path separators. |
voicevox_url |
URL | empty | reboot | HTTP base URL (http://ip:port) of a self-hosted VoiceVox / API-compatible TTS engine. Empty disables the synthesis task. IPv4-literal only — no DNS. See voice. |
voicevox_speaker_id |
u16 | 1 |
reboot | VoiceVox speaker (voice) ID. 1 is Zundamon “ノーマル”; query the engine’s GET /speakers for the catalogue. Ignored when voicevox_url is empty. |
Reboot semantics: every field marked live takes effect on the
next render frame (PUT /settings immediately signals the relevant
task). Fields marked reboot are read once at task spawn and need
a power-cycle or POST /restart to pick up the new value. PUT /settings
echoes {"reboot_required": <bool>} so operators don’t have to
remember the table.
Workflows
Edit + apply via the dashboard
Open http://<hostname>.local/ in a LAN browser; the embedded
dashboard surfaces the same behavior: block as form fields,
posts via PUT /settings, and shows reboot_required: true as a
banner when relevant.
Edit + apply via the SD card
Power off the avatar, mount the SD card on the host, edit
/STACKCHAN.RON directly, eject, power on. RON is more permissive
about formatting than JSON — multi-line values, trailing commas,
comments are all fine. The firmware re-validates on boot; a malformed
file falls back to the offline defaults and logs the failure over
USB-Serial-JTAG.
Edit + apply via curl
# Round-trip the current config (PSK + tokens redacted as "***")
curl -sS http://stackchan.local/settings > settings.json
$EDITOR settings.json
curl -sS -X PUT --data-binary @settings.json \
-H 'Content-Type: application/json' \
http://stackchan.local/settings
The redacted "***" sentinel echoes back unchanged on PUT and
the firmware substitutes the persisted value — leave wifi.psk,
auth.token, behavior.agent_sidecar_token, and the esp_now.*_hex
fields alone unless you actually want to rotate them.
Confirm what the firmware actually has
curl -sS http://stackchan.local/settings | jq .behavior
GET /settings is authoritative for the persisted config. Live
task state (e.g. whether the wake-word task actually loaded the
model file) shows up in defmt logs over USB-Serial-JTAG; the HTTP
control plane doesn’t currently mirror task health back as
structured data.
Adding a new behavior field
Three files change in lockstep:
crates/stackchan-net/src/config.rs— add the field toBehaviorConfigwith a doc comment, then updateDefaultso omitting the block keeps the new field’s default consistent with the in-parser fallback.crates/stackchan-net/src/bare.rs+bare_json.rs— render- parse arms with a duplicate-key guard. Both backends have a
parse_behaviortest fixture; extend both.
- parse arms with a duplicate-key guard. Both backends have a
crates/stackchan-firmware/src/net/http.rs— if the field is read once at boot (task spawn time), add it torequires_reboot. If the field has invalid values, extendvalidate()instackchan-netwith a typedConfigErrorvariant + a regression test for the rejection.
Greptile reliably flags missing requires_reboot entries and
missing validate guards — both have bitten this repo before
(see PRs around #354 for the latest combined audit). When in doubt,
add both gates.
Related
- HTTP control plane — full route surface;
PUT /settingssemantics and the redacted-field round trip. - Sidecar agent — wire protocol for
agent_sidecar_url/agent_sidecar_token. - Voice agent onboarding — end-to-end flow for wake word
- sidecar.
- UDP audio debug — receive recipe for
audio_debug_udp_target.