# KUYASE (К.У.Я.С.Э.) — Кустарный Универсальный Яндекс Станции Эмулятор

> Native cross-platform desktop application (`eframe`/`egui`) and CLI hardware-in-the-loop QEMU (`qemu-system-aarch64`) emulator for Yandex Station smart speakers running Linux Buildroot firmware (Amlogic SoCs). Provides kernel/userspace peripheral emulation (`SN3236` I2C LEDs, `vfb` framebuffers, `sysfs` LEDs/clocks, `uinput` buttons/ToF, `IIO`/`thermal` sensors, `snd-aloop` ALSA audio), local Quasar Protobuf IPC stubs (`aliced` `:9875`, `yio_audio` `:9850`, `iohub_services` `:9903`), ADB root access (`:15555`), a userspace `.ext4` image builder, a built-in Rust ADB client (`:5555`), and the 60 FPS `Virtual Speaker Twin` desktop workspace connected over a duplex TCP stream (`:18091 -> :8091`).

## Documentation Index

- [README.md](./README.md): Quickstart, source build instructions (Windows/Linux), GUI/CLI usage, supported/unsupported device tables, and emulated subsystems.
- [CONTEXT.md](./CONTEXT.md): Canonical domain glossary (`Board Profile`, `Board Peripherals`, `Firmware Dump`, `Guest Image`, `Hardware Bridge`, `Virtual Speaker Twin`, `Register Latch`, `Stealth Lock`, `Trigger Conflict`, `Hijack Window`, `Formant TTS Synthesizer`).
- [protocol/src/lib.rs](./protocol/src/lib.rs), [protocol/src/boards.rs](./protocol/src/boards.rs), [protocol/src/display.rs](./protocol/src/display.rs): Duplex TCP bridge protocol contracts (`[u8 kind][u32_le len][payload]` on `:8091` / `:18091`), `BridgeStateSnapshot`, `HostCommand`, `GuestPacket`, canonical `BOARD_CATALOG` (`BoardDescriptor`), and shared 7-segment / `21×12` matrix display rendering.
- [DUMP_GUIDE.md](./DUMP_GUIDE.md): Extracting clean `rootfs.tar.gz` dumps over network ADB (`:5555`) via standalone scripts (`scripts/dump-from-adb.sh` / `.ps1`), manual `adb`, or `kuyase dump`, and building `.ext4` images in userspace via `kuyase prepare`.
- [tests_e2e/README.md](./tests_e2e/README.md): End-to-end smoke test suite (`yam`, `luna`, `station.airplay`, and `/system/vendor/quasar/q`).
- [AGENTS.md](./AGENTS.md): Agent workflow rules, cross-compilation/injection pipeline, and hardware emulation invariants.

## Repository Layout (3-Crate Cargo Workspace)

- `protocol/`: Shared protocol and domain crate compiled for both host (`x86_64`/`aarch64`) and guest (`armv7-unknown-linux-musleabihf`).
  - `protocol/src/lib.rs`: `BridgeStateSnapshot`, `AmplifierSlotState`, `UltrasoundState`, `HostCommand`, `GuestPacket` (`StateSnapshot`, `PcmAudioChunk`, `CommandAck`), length-prefixed framing (`[u8 kind][u32_le len][payload]`), and WAV builder.
  - `protocol/src/boards.rs`: Canonical `BOARD_CATALOG: &[BoardDescriptor]` (`slug`, `board_name`, `gui_label`, `sysfs_prefix`, `ring_leds`, `ring_driver`, `ring_fb_dev`, `logo_leds`, `ambilight_leds`, `has_clock`, `has_matrix_21x12`, `has_battery`, `has_ultrasound`) and SoC/DT-first board detection (`detect_board_slug_from_probe`, `normalize_board_slug`).
  - `protocol/src/display.rs`: Shared 7-segment clock (`build_segments_map_from_text`, `parse_clock_segment_spec`, `parse_display_led_frame`) and `21×12` matrix (`glyph_4x7`, `render_text_to_matrix_21x12`) rendering.
- `hw-bridge/`: Guest `qemu-hw-bridge` daemon crate (statically compiled for `armv7-unknown-linux-musleabihf` via `rust-lld` so one binary runs on both 32-bit `armhf` and 64-bit `aarch64` guests).
  - `hw-bridge/src/main.rs`: Entrypoint, multi-call stub applet dispatch (`quasar_launcher2`, `maind`, `begemot`, `--dbus-stub`), `/dev/uinput` creation, thread startup.
  - `hw-bridge/src/runtime_env.rs`: Guest runtime environment preparation (`quasar_launcher2` supervisor stub, `/tmp/.kuyase-stubs` RAM bind-mounts for `quasar.cfg` `"devConfig"` and ALSA `Verneed`, `/var/run -> /run` unification, `dbus-daemon-launch-helper` `04750` `0:85`, `wlan0` netdev, unified `maind.log` symlinks).
  - `hw-bridge/src/dbus_stub.rs`: Zero-dependency D-Bus wire-protocol responder for `org.bluez` (`GetManagedObjects`, `/org/bluez/hci0`, `org.bluez.LEAdvertisingManager1`, `org.bluez.GattManager1`) and `org.bluealsa` on `/run/dbus/system_bus_socket` in `Full Mode`.
  - `hw-bridge/src/state.rs`: `BoardProfile` auto-detection (backed by `protocol::find_board_descriptor`), vendor volume mirroring (`0..20` <-> `0..10`), and shared `BridgeState`.
  - `hw-bridge/src/devices/`: Trait-based peripheral abstraction (`BoardPeripherals` in `devices/mod.rs`):
    - `devices/led_ring.rs`: `LedRingDevice`, `Sn3236I2cRing` (`0x3c` BGR + `0x25` latch), `SysfsFbLedRing` (`[ledfb-ring]` trigger conflict guard).
    - `devices/aux_light.rs`: `AuxLightDevice`, `OrionAmbilightDevice` (`12×2` RGBW `/dev/fb0`), `LogoSysfsFbDevice`, `NullAuxLight`.
    - `devices/front_display.rs`: `FrontDisplayDevice`, `SegmentClockSysfsDisplay`, `OrionMatrix21x12Display` (`21×12` monochrome LED screen `/dev/fb1`), `NullFrontDisplay`.
    - `devices/audio_hw.rs`: `AudioSubsystemDevice`, `OrionQuadAcm8625Audio` (`4× ACM8625S` + `96 kHz / 38.4 kHz` Ultrasound TDM), `GenericAlsaAudio`.
  - `hw-bridge/src/leds.rs`: `.led` animation parser/player (`ring` & `ambilight`) and volume arc generator.
  - `hw-bridge/src/tts.rs`: Pure procedural Russian Formant TTS synthesizer (Rosenberg glottal source + 4-formant Klatt cascade/parallel resonator bank, Russian orthoepy, proclitic merging, and 3-point `IK-1/2/3` pitch contours).
  - `hw-bridge/src/audio.rs`: ALSA `snd-aloop` (`hw:0,1`) capture, live `PcmAudioChunk` broadcast to connected duplex clients, chunked TTS playback with `STOP_TTS` interruption, 440 Hz test tone, `libasound_module_ctl_Saved.so` stub generator, and RAM-mounted ALSA symbol-version compatibility.
  - `hw-bridge/src/input.rs`: Linux `uinput` device creation, `EV_KEY` / `EV_ABS` event injection, and interactive `/bin/sh -i` root console on `/dev/ttyAMA0` with `setsid()`, `TIOCSCTTY`, `TIOCSWINSZ`, and `iutf8`.
  - `hw-bridge/src/voice_dialog.rs`: Voice injection dialog state machine (`InjectVoice`), `1680 ms` hijack window, Luna `:8099` (`/api/volume/set`) sync, AirPlay D-Bus transport fallback (`/run/station-airplay/private-bus`), and `IpcTest`.
  - `hw-bridge/src/ipc.rs`: TCP servers for Quasar IPC (`:9875` `aliced`, `:9850` `yio_audio`, `:9903` `iohub_services`, `:9899` `glagold`) and `AliceState` event broadcasting.
  - `hw-bridge/src/glagol.rs`: Internal `glagold` Protobuf IPC server (`127.0.0.1:9899`) and external Glagol local API server (`0.0.0.0:1961`, HTTP `GET /` & RFC 6455 WebSocket JSON).
  - `hw-bridge/src/proto.rs` & `hw-bridge/src/proto/{quasar_root,remoting,alice,iohub,glagol}.rs`: Zero-dependency multi-generation Protobuf wire encoder/decoder for `QuasarMessage` (`[u32_le_len][payload]`, supporting both `<= 0.367` `LegacyDirect` and `>= 0.368` `Envelope252` `LITE_RUNTIME` wire formats).
  - `hw-bridge/src/bridge_server.rs`: Duplex TCP server (`:8091` in guest -> `:18091` on host) pushing `GuestPacket::StateSnapshot` and `GuestPacket::PcmAudioChunk` frames and dispatching `HostCommand` requests.
- `kuyase/`: Host desktop GUI application (`eframe`/`egui`) and CLI runner crate.
  - `kuyase/src/main.rs`: CLI entrypoint (`kuyase`, `kuyase run --headless [--board <slug|all>] [--exec "<cmd>"] [--keep-alive] [--mode <stub|full>]`, `kuyase test`, `kuyase dump <ip>`, `kuyase prepare`).
  - `kuyase/src/session.rs` & `kuyase/src/serial_vt100.rs`: `EmulatorSession` managing `qemu-system-aarch64` child process lifecycle, byte-level VT100/ANSI `SerialScreenBuffer` (`SerialSnapshot`) over `ttyAMA0` with UTF-8 boundary-aligned UART chunking, secondary `virtio-blk` bridge injection, and `-snapshot` overlay mode.
  - `kuyase/src/bridge_client.rs`: Persistent duplex TCP client (`BridgeClient`) receiving `StateSnapshot` and `PcmAudioChunk` packets and sending `HostCommand` requests.
  - `kuyase/src/adb.rs`: Pure-Rust ADB TCP protocol client (`CNXN`, `OPEN`, `WRTE`, `CLSE`, `shell:`, and `sync:` `RECV`/`DATA`).
  - `kuyase/src/dumper.rs`: Network ADB firmware dumper (`kuyase dump <ip[:5555]>`) with automatic partition space probing and secret scrubbing.
  - `kuyase/src/rootfs_tree.rs`, `kuyase/src/image_builder.rs`, `kuyase/src/archive_formats.rs` (`archive_formats/{ubifs,squashfs}.rs`) & `kuyase/src/ext_fs.rs`: Userspace `Guest Image` (`work/<board>-system.ext4`) builder supporting `rootfs.tar.gz`, `.tar`, `.zip`, `system.img[.gz]`, and `ubi0_0_rootfs.img` / `mtd3_system.bin` UBIFS/UBI dumps without WSL2 or `sudo mount -o loop`.
  - `kuyase/src/test_suite.rs`: Modularized multi-board hardware, native `ttyAMA0` `/bin/sh`, and Quasar IPC verification suite (`kuyase test`).
  - `kuyase/src/gui/`: GNOME Libadwaita-inspired desktop workspace (`work/kuyase-ui.json`), 60 FPS `Virtual Speaker Twin` vector canvas and interactive faceplates (`canvas.rs`, `faceplates.rs`, `display_geom.rs`), signal monitor & native `ttyAMA0` `/bin/sh` terminal dock (`terminal.rs`, `signal_log.rs`), host audio playback & `.wav` recorder (`host_audio.rs`), modular action cards (`docks/{mod,voice_audio,sensors_tof,board_cards}.rs`), OS file dialogs (`os_dialogs.rs`), and modal image/dump/QEMU manager (`launcher.rs`).
- `schemas/quasar/quasar.proto`: Canonical multi-generation `.proto` schema definitions for `QuasarMessage`, `Remoting`, `AliceState`, `IOControlCommand`, and `GlagoldState`.
- `tests_e2e/`: End-to-end smoke suite (`harness.py`, `test_01_yam.py`, `test_02_luna.py`, `test_03_airplay.py`, `test_04_quasar_q.py`) verifying real `yam`, `luna`, `station.airplay` installers and unmodified `/system/vendor/quasar/q` commands via `kuyase run --headless --board <board> --snapshot --exec`.
- `scripts/`: Standalone dump extraction and sanitization scripts (`dump-from-adb.sh`, `dump-from-adb.ps1`, `sanitize-rootfs.sh`, `sanitize-rootfs.ps1`) and Protobuf Rust module generator (`gen_quasar_proto.py` from `schemas/quasar/quasar.proto`).
- `guest-init/equasar-qemu-init.sh`: Guest `PID 1` (`/quasar-qemu-init.sh`) that mounts virtual filesystems, spoofs `/proc/device-tree`, synthesizes `/sys/class/leds/*`, `/sys/class/graphics/fb0..2`, `/sys/bus/i2c/devices/*`, `/sys/class/power_supply/ya_pd`, and ALSA devices (`pcm.speakers`, `pcm.ultrasound`, `pcm.bluetooth`), starts `/usr/bin/adbd` (`:5555`), and launches `/usr/local/bin/qemu-hw-bridge`.
- `kernel/build-kernel.sh`: Builds Linux `6.6.60` `arm64` (`kernel/Image`) with `CONFIG_COMPAT=y`, `snd-aloop`, `uinput`, patched `drivers/i2c/i2c-stub.c`, and 3-framebuffer `drivers/video/fbdev/vfb.c` (`fb0`, `fb1`, `fb2`).

## Supported Board Profiles (`board_slug`)

### Tested Profiles
- `yandexmini` (Станция Мини, `YNDX-0004`, 32-bit `armhf`): 6-LED ring via I2C `SN3236` (`0x3c` on `/dev/i2c-0`), `VL53L0X` ToF sensor, 4 mics.
- `yandexmini2` (Станция Мини 2 с часами, `YNDX-00021`, 32-bit `armhf`): 6-LED ring (`mini2:*:ring1..6`), 7-segment clock (`mini2:white:clock*`), `LTR-308` ALS, 4 mics.
- `yandexmini2nc` (Станция Мини 2 без часов, `YNDX-00020`, 32-bit `armhf`): 6-LED ring (`mini2:*:ring1..6`), `LTR-308` ALS, 4 mics.
- `bergamot` (Станция Мини 3, `YNDX-00027`, 32-bit `armhf`): 6-LED panel (`/dev/fb0` or `bergamot:*:ring0..5`, `AW21018`, `ledpatterns/oknix/*.led`), 32-segment clock (`bergamot:white:clock{A..G}{0..3}`, `clockDH`, `clockDL`, `clockDM`, `clockDEGREE`, `AW21036`), `ACM8625P` Class-D amplifier (`2-002c`, `bergamot-acm8625.cfg`), `LTR-308` ALS, USB-C PD (`husb238_pd` `12V`), 3 mics.
- `pickle` (Станция Мини 3 Про, `yandex,pickle`, 64-bit `aarch64`): 16-LED ring (`/dev/fb0` `name="ring"` or `pickle:*:ring0..15`, `ledpatterns/ring/*.led`), 6-LED logo `oknix` (`/dev/fb1` `name="logo"` or `pickle:*:logo0..5`, `ledpatterns/oknix/*.led`), 32-segment clock (`pickle:white:clock{A..G}{0..3}`, `clockDH`, `clockDL`, `clockDM`, `clockDEGREE`, `2-0034`), `ACM8625` Class-D amplifier (`2-002c`, `pickle-acm8625-psy02272001.cfg`), `AW933XX` touch controller (`3-0012`), `LTR-308` ALS, USB-C PD (`husb238_pd` `12V`), 3 mics.
- `yandexmicro` (Станция Лайт, `YNDX-00025`, 32-bit `armhf`): 3-LED ring (`micro:*:ring1..3`), 4 mics.
- `plum` (Станция Лайт 2 с часами, `yandex,plum`, 32-bit `armhf`): 3-LED ring (`plum:*:ring1..3`), 7-segment clock (`plum:white:clock*`), `LTR-308` ALS, 2 mics.
- `plumnc` (Станция Лайт 2 без часов, `yandex,prune`, 32-bit `armhf`): 3-LED ring (`plum:*:ring1..3`), `LTR-308` ALS, 2 mics.
- `mango` (Станция Стрит, `yandex,mango`, 32-bit `armhf`): 4-LED battery indicator (`/dev/fb0` or `mango:*:ring1..4`, `AW9110`, `ledpatterns/battery/*.led`), 3-LED RGBW logo `oknix` (`/dev/fb1` or `mango:*:logo0..2`, `AW21012`, `ledpatterns/oknix/*.led`), `ACM8625S` Class-D amplifier (`2-002c`, `mango-acm8625.cfg` / `mango-acm8625-outside.cfg`), `CW2217` battery fuel gauge & `IP2366` USB-C PD charger, `SC7A20TR` accelerometer, 2 mics.
- `station2` (Станция 2, `YNDX-00051` / `yandex,station-midi`, 32-bit `armhf`): 88-LED RGBW panel (`/dev/fb0` or `station2:*:ring0..87`), `LTR-308` ALS, 4 mics.
- `cucumber` (Станция Миди, `YNDX-00054`, 64-bit `aarch64`): 24-LED ring (`/dev/fb0` or `cucumber:*:ring0..23`), 6-LED logo (`/dev/fb1` or `cucumber:*:logo0..5`), 7-segment clock (`cucumber:white:clock-*`), `LTR-308` ALS, 4 mics.
- `orion` (Станция 3, `YNDX-00055`, 64-bit `aarch64`): 36-LED ring (`/dev/fb2` `name="ring"` or `orion:*:ring0..35` + `orion:ring{A,B,C}:sync`), 12×2 RGBW ambilight (`/dev/fb0` `name="ambilight"`, `12×1` `48 bpp` + 96 sysfs channels `orion:{red,green,blue,white}:ambilight{0..11}{a,b}` + `orion:ambilight{A,B,C}:sync`), `21x12` monochrome LED matrix display (`/dev/fb1` `name="YNDX LED screen"`, `252` pixels, `756` bytes `24 bpp`, `gowin_led_device.ko`), 4× `ACM8625S` Class-D amplifiers (`3-002d` `woofer`, `3-002e` `lr`, `3-002c` `center`, `2-002c` `us`), separate Ultrasound TDM-A (`hw:0,0` / `pcm.ultrasound`, `96 kHz` sample rate, `38.4 kHz` carrier), `light-sensor-top` (`LTR-308`) ALS, USB-C PD (`husb238_pd` `20V`), 6 mics.

### Auto-Profiled (Untested)
- `saturn` (Умный хаб Яндекса, `armhf`).

### Unsupported Devices
- Android / YaOS devices (`tulip-d1` Станция 1, `yandexstation_2` Станция Макс / Макс с Zigbee, Станция Дуо Макс, ТВ Станции) are not supported.

## Guest Hardware & IPC Interfaces (Inside QEMU)

### 1. Trait-Based Peripherals (`hw-bridge/src/devices/`)
All board-specific hardware peripherals are encapsulated behind 4 `Send + Sync` traits in `BoardPeripherals`:
- **`LedRingDevice`**:
  - `Sn3236I2cRing` (`yandexmini`, bus `/dev/i2c-0`, address `0x3c`):
    - `0x00`: Shutdown register (`bit 0`: `1` = normal operation, `0` = software shutdown).
    - `0x01..0x12`: 18 PWM brightness registers for 6 LEDs in **BGR** order (`LED i`: `B = 0x01 + i*3`, `G = 0x02 + i*3`, `R = 0x03 + i*3`).
    - `0x25`: PWM & Control Update register (`Register Latch`). Writing any byte latches shadow values from `0x01..0x12` and `0x26..0x37` to the active LEDs.
    - `0x26..0x37`: 18 LED Control registers (`bit 0` = `OUT_EN`, `bits 2:1` = `SL` current divider: `00` = `Imax`, `01` = `Imax/2`, `10` = `Imax/3`, `11` = `Imax/4`).
    - `0x4a`: Reset register. Writing any byte clears all registers (`0x00..0x4b`) and turns off all LEDs.
  - `SysfsFbLedRing` (`orion`, `cucumber`, `yandexmini2`, `yandexmicro`, etc.):
    - Resolves ring framebuffer by `/sys/class/graphics/fb*/name == "ring"` (`/dev/fb2` on `orion`, `/dev/fb0` on others).
    - Direct writes to `/sys/class/leds/<prefix>:<color>:ring<N>/brightness` (`0..255`) require setting `trigger` to `none` first (`echo none > trigger`). Writing `brightness` while `[ledfb-ring]` is active increments `led_trigger_conflict_count` (`Trigger Conflict`) and is rejected.
- **`AuxLightDevice`**:
  - `OrionAmbilightDevice` (`orion`): 12 dual-channel RGBW zones via `/dev/fb0` (`name = "ambilight"`, `12×1`, `48 bpp`, 72 bytes) and `/sys/class/leds/orion:{red,green,blue,white}:ambilight{0..11}{a,b}` + `/system/vendor/quasar/ledpatterns/ambilight/*.led`.
  - `LogoSysfsFbDevice` (`cucumber`, `pickle`, `mango`): `logo0..N` in `/sys/class/leds/<prefix>:*:logo*`.
- **`FrontDisplayDevice`**:
  - `SegmentClockSysfsDisplay` (`yandexmini2`, `cucumber`, `bergamot`, `pickle`, `plum`): 7-segment clock `/sys/class/leds/<prefix>:white:clock*` (`a1..g4`, `p3`, `q3`, `h1`, `m1`, `deg`).
  - `OrionMatrix21x12Display` (`orion`): Monochrome LED dot-matrix `21×12` (`252` pixels) on `/dev/fb1` (`name = "YNDX LED screen"`, `756` bytes `24 bpp`, `gowin_led_device.ko`). Renders `4×7` glyphs (`OrionFrontPanelLedFrameBuilder`), volume overlay, and matrix `.led` animations (`pattern:joy`, `pattern:volume`, `pattern:mute`) from `/system/vendor/quasar/ledpatterns/screen/`.
- **`AudioSubsystemDevice`**:
  - `OrionQuadAcm8625Audio` (`orion`): Emulates 4× `ACM8625S` I2C Class-D amplifiers (`3-002d` `woofer` -> `orion-acm8625-woofer.cfg`, `3-002e` `lr` -> `orion-acm8625-lr.cfg`, `3-002c` `center` -> `orion-acm8625-center.cfg`, `2-002c` `us` -> `orion-acm8625-us.cfg`) with `hardvold` gain curve (`-66.6 .. 0.0 dB`, ramp `-6 dB`) and separate TDM-A Ultrasound (`hw:0,0` / `pcm.ultrasound`, `96000 Hz`, `38400 Hz` carrier, `600 Hz` bandwidth, 4 channels).

### 2. Input Devices (`/dev/input/event0..2`)
- `event0`: `"STM VL53L0 proximity sensor"` (`EV_ABS`: `ABS_DISTANCE = 0x19`, `0x12` in mm).
- `event1`: `"AML-AUGESOUND Headphones"` (`EV_SW`).
- `event2`: `"adc_keypad"` (`EV_KEY`: `KEY_MUTE = 113`, `KEY_VOLUMEDOWN = 114`, `KEY_VOLUMEUP = 115`, `KEY_VOICECOMMAND = 582`).

### 3. Sensors (`sysfs` / `IIO`)
- SoC Temperature: `/sys/class/thermal/thermal_zone0/temp` (millidegrees Celsius, e.g. `42500` = `42.5 °C`).
- Ambient Light (`ALS`): `/sys/bus/iio/devices/iio:device0/in_illuminance_raw` (lux).
- ADC Voltage: `/sys/bus/iio/devices/iio:device0/in_voltage6_mean_raw`.

### 4. Audio (`ALSA` & Formant TTS)
- Loopback card `Loopback` (`snd-aloop`): playback to `default` (`hw:0,0,0` + `softvol` control `Master` `0..10000`) is captured by `qemu-hw-bridge` from `hw:0,1,0` (`48000 Hz`, `S16_LE`, stereo, with 400 ms inter-word pause hangover) and pushed live to the host over `GuestPacket::PcmAudioChunk`.
- Ultrasound TDM (`pcm.ultrasound` on `hw:0,0,2`, `96000 Hz`, stereo/4ch, `softvol` control `Ultrasound Playback Volume`).
- Expressive Russian Formant TTS (`hw-bridge/src/tts.rs`): procedural synthesis (number expansion, proclitic merging, Russian orthoepy/palatalization, Bryzgunova `IK-1/2/3` 3-point pitch contours, Rosenberg glottal pulse + 4-formant Klatt cascade/parallel resonator bank) streamed to ALSA in `40 ms` chunks with immediate `STOP_TTS` / `CANCEL_DIALOG` interruption.

### 5. Local Quasar IPC Sockets & Logs
In `Stub Mode` (`quasar.mode=stub`), `qemu-hw-bridge` emulates the `maind` Protobuf IPC sockets (based on [`v3rt3p/quasar-protos`](https://github.com/v3rt3p/quasar-protos)) using little-endian length-prefixed framing `[u32_le_len][QuasarMessage protobuf]`:
- `127.0.0.1:9875` (`aliced`): Accepts `QuasarMessage.remoting (field 210)`:
  - `AliceCapability`: `method = 6` (`CANCEL_DIALOG_AND_CLEAR_QUEUE`) or `method = 14` (`STOP_TTS`) cancels active dialog within the `1680 ms` Hijack Window (`aliced_hijack_count++`) or interrupts active TTS; `method = 18` (`START_VOCALIZE` with `vocalize_directive -> Text`) synthesizes speech in ALSA (`aliced_say_count++`, sets `last_spoken_text`).
  - `DeviceStateCapability`: updates `mics_muted`.
  - `PlaybackControlCapability` & other `Remoting` capabilities: validated and logged (malformed Protobuf increments `ipc_error_count`).
- `127.0.0.1:9850` (`yio_audio`): Streams `QuasarMessage.mic_input_data (field 158)` (`IOAudioChannelData`: `raw_mic_0..3`, `vqe_0`, `doa_angle` in fields `5`/`6`) every `40 ms` to subscribed clients.
- `127.0.0.1:9903` (`iohub_services`): Accepts `IOControlCommand` packets (`RetrieveStateHandshake`, `ServiceReady`, `external_directives` JSON, `IoControlField`).
- `127.0.0.1:9899` (`glagold`): Accepts `GlagolDiscoveryRequest` (`type = 185`, including `debug_connections = 8` from `q glagol-connections` -> replies with `LogMessage` `type = 184` JSON and `GlagoldState` `type = 82`) and `GlagolClusterMessage` (`type = 181`).
- `0.0.0.0:1961` (External Glagol HTTP / WebSocket server): Serves `GET /` JSON device descriptor and RFC 6455 WebSocket JSON commands (`ping`, `state`, `play`, `pause`, `stop`, `next`, `prev`, `setVolume`, `sendText`, `tts`) on port `:1961` (forwarded to host as `127.0.0.1:11961`).
- `/tmp/daemons_logs/maind.log` (symlinked to `/data/quasar/daemons_logs/maind.log` and `/bkupgrade/data/quasar/daemons_logs/maind.log`): Receives `[sdk] onRequestStateChanged: LISTENING, recognizedPhrase='...'` lines upon voice injection.

## Host Ports & Duplex Bridge Protocol (`protocol/src/lib.rs`)

- `127.0.0.1:15555` -> Guest `:5555` (ADB root shell: `adb connect 127.0.0.1:15555` or internal `kuyase::adb::AdbClient`).
- `127.0.0.1:18090` -> Guest `:8090` (Forwarded port for custom guest services/SDKs).
- `127.0.0.1:18091` -> Guest `:8091` (Duplex TCP stream with 5-byte header `[u8 kind][u32_le payload_len][payload]`):
  - **Guest -> Host (`GuestPacket`)**:
    - `kind = 1` (`StateSnapshot`): JSON-encoded `BridgeStateSnapshot`.
    - `kind = 2` (`PcmAudioChunk`): Raw `48000 Hz`, `S16_LE`, 2-channel PCM audio bytes.
    - `kind = 3` (`CommandAck`): JSON-encoded `CommandAckPayload { ok, error, message }`.
  - **Host -> Guest (`HostCommand`, `kind = 1`)**:
    - `RequestState`
    - `PressButton { button: "action"|"mute"|"volume_up"|"volume_down", action: "single"|"double"|"triple"|"long" }`
    - `SetVolume { volume_level: 0..10 }`
    - `SetLedPattern { pattern: "alice_listening.led"|"" }`
    - `SetClockDisplay { segments, replace, pixels, led_frame, brightness, scale_brightness, text }`
    - `SetSensor { doa_angle, mic_rms, als_lux, temp_c, tof_mm, swipe, swipe_direction }`
    - `InjectVoice { phrase, doa_angle, rms, wake_only }`
    - `IpcTest { cmd: "cancel_dialog"|"stop_tts"|"vocalize", text }`
    - `PlayTestTone`
    - `ClearAudio`
    - `PowerOff`
