I have everything I need. The entrypoint signature is def run(self, reachy_mini: ReachyMini, stop_event: threading.Event) -> None, subclassing ReachyMiniApp. I have enough — let me write up the report.
Reachy Mini SDK — Research Report
1. Installation
Install via uv (recommended) or pip from PyPI. Package name is reachy-mini (PyPI) which imports as reachy_mini.
Python 3.10–3.12 supported. On Linux you also need GStreamer + USB udev rules. Source: https://raw.githubusercontent.com/pollen-robotics/reachy_mini/main/docs/source/SDK/installation.md
2. Instantiating the Robot
Class is ReachyMini. No host/IP arg needed — it auto-detects USB/localhost vs network. Use as a context manager:
Optional override: ReachyMini(connection_mode="localhost_only" | "network") and ReachyMini(robot_name="..."). There is no host=/ip= argument in the public surface — connection is mediated by the local daemon (localhost:8000 for Lite, reachy-mini.local:8000 for Wireless).
3. Speaking text out loud — there is NO .speak() / .tts() / .audio.play()
Confirmed from docs/source/SDK/python-sdk.md: the SDK exposes raw audio I/O only. You generate audio with an external TTS lib, then push float32 samples to the speaker via mini.media.push_audio_sample(...). Verbatim from the docs:
Notes from the doc:
push_audio_sample() expects shape (samples, 1 or 2), dtype float32, 16 kHz.
- It is non-blocking — sleep for
len(samples)/samplerate to wait for playback.
- Use
mini.media.get_output_audio_samplerate() to confirm the rate; resample if your TTS produces 22.05 / 24 kHz.
For "good morning" the simplest stack: Piper or pyttsx3 → WAV → load with soundfile/scipy.io.wavfile → convert to float32 mono → resample to 16 kHz → mini.media.push_audio_sample(samples). (The conversation app uses OpenAI/Gemini Realtime APIs that stream PCM directly into push_audio_sample.)
4. App Framework — pyproject entry point
A Reachy Mini app is a Python package registered through a setuptools entry point group named reachy_mini_apps, exposing a class that subclasses reachy_mini.ReachyMiniApp and implements run(self, reachy_mini, stop_event).
Do not scaffold by hand — the official tool is:
Generated layout (verbatim from skills/create-app.md):
The required pyproject.toml block (from the conversation app):
The required class signature (verbatim from reachy_mini_conversation_app/main.py):
The README YAML frontmatter must carry the discovery tag reachy_mini (and reachy_mini_python_app for Python apps) for the HF app store to pick it up.
5. The "Button" — use the antennas
Reachy Mini has no physical button, but per the official AGENTS.md: "Antennas: 2 motors, also usable as physical buttons." They use low-P PID so they are semi-passive and safe to push. The canonical pattern (verbatim from skills/interaction-patterns.md):
Reference implementation: reachy_mini_simon (no-GUI app driven entirely by antenna presses) at https://huggingface.co/spaces/apirrone/reachy_mini_simon. Tip from the docs: debounce with a cooldown.
If antennas don't fit the use case, alternatives that are also documented as supported:
- Web UI button: put
static/index.html with a button that hits the daemon REST API (http://localhost:8000/docs) or your own FastAPI mounted in run().
- Keyboard input: plain
input() / keyboard lib — fine for a quick local demo, but not "appy".
Recommended minimal app for your use case
Antenna-as-button + Piper TTS in a ReachyMiniApp subclass: scaffold with reachy-mini-app-assistant create good_morning . --publish, then in good_morning/main.py poll check_antenna_press(reachy_mini) and on press: synthesize "good morning" with Piper to a numpy float32 mono buffer at 16 kHz and call reachy_mini.media.push_audio_sample(samples) (after start_playing()). Loop until stop_event.is_set().
Key links