app: id: pine name: Pine version: "1.3.0" description: A private voice assistant for your home. Pine runs speech-to-text (Whisper), text-to-speech (Piper) and wake-word detection (openWakeWord) on your own node and pairs with a PineVoice satellite speaker, so Home Assistant Assist works locally with nothing sent to the cloud. Ask it about your node — block height, sync, peers, Lightning balance — and, when a Claude API key is set, anything else. category: home # The user-facing launcher (app_id + container both "pine", matching the # runtime references + the live container so the orchestrator adopts it). A # tiny nginx that serves the "Connect Pine to WiFi" provisioner page for the # voice stack. The two Wyoming engines (pine-whisper, pine-piper) are internal # stack members. container_name: pine container: image: docker.io/library/nginx:1.27-alpine pull_policy: if-not-present network: archy-net network_aliases: [pine] # The provisioner uses Web Bluetooth (Improv-over-BLE) to push WiFi creds to # the PineVoice speaker. navigator.bluetooth only exists in a SECURE CONTEXT # (https or localhost), so the launcher terminates TLS with a self-signed # cert — otherwise the "Connect Pine to WiFi" button is inert on the LAN. # Idempotent: kept as-is when crt+key already exist. Mirrors the netbird # secure-context fix (#15). generated_certs: - crt: /var/lib/archipelago/pine/tls.crt key: /var/lib/archipelago/pine/tls.key dependencies: - app_id: pine-whisper - app_id: pine-piper - app_id: pine-openwakeword - storage: 128Mi resources: memory_limit: 64Mi security: # cap-drop=ALL is applied by the orchestrator. nginx (master as root, drops # workers) binds :443 inside the container — needs the worker-drop caps + # NET_BIND_SERVICE for the privileged port. capabilities: [CHOWN, DAC_OVERRIDE, SETGID, SETUID, NET_BIND_SERVICE] readonly_root: false no_new_privileges: true network_policy: isolated ports: # 10380 (http) is the Open target — the UI launches apps as # http://host:10380 (resolveAppUrl). nginx there 301-redirects to the https # listener on 10381, so the new tab lands on a secure context where # navigator.bluetooth (the "Connect Pine to WiFi" provisioner) works. - host: 10380 container: 80 protocol: tcp - host: 10381 container: 443 protocol: tcp volumes: - type: bind source: /var/lib/archipelago/pine/nginx.conf target: /etc/nginx/conf.d/default.conf options: [ro] - type: bind source: /var/lib/archipelago/pine/tls.crt target: /etc/nginx/tls.crt options: [ro] - type: bind source: /var/lib/archipelago/pine/tls.key target: /etc/nginx/tls.key options: [ro] - type: bind source: /var/lib/archipelago/pine/index.html target: /usr/share/nginx/html/index.html options: [ro] environment: [] files: - path: /var/lib/archipelago/pine/nginx.conf overwrite: true content: | server { listen 80; server_name _; return 301 https://$host:10381$request_uri; } server { listen 443 ssl; server_name _; ssl_certificate /etc/nginx/tls.crt; ssl_certificate_key /etc/nginx/tls.key; root /usr/share/nginx/html; index index.html; # Live node facts for the status card — proxied to the node's # public status tier so the (https) page can fetch same-origin. location = /node-status { proxy_pass http://host.containers.internal:80/api/pine/status; proxy_http_version 1.1; proxy_set_header Host $host; proxy_connect_timeout 5s; proxy_read_timeout 10s; } location / { try_files $uri $uri/ /index.html; } } - path: /var/lib/archipelago/pine/index.html overwrite: true content: | Pine — connect your speaker

Pine

Connect your speaker — everything stays on your node.

Whisperspeech-to-text ready on :10300
Pipertext-to-speech ready on :10200
Wake word“Hey Jarvis” on the speaker (openWakeWord on :10400)
Speakerput it in pairing mode — ring LED blinking yellow
Nodechecking…
Bitcoin
Peers
This page isn’t running over HTTPS, so the browser blocks Bluetooth. Open it via its https://…:10380 address (accept the self-signed certificate) and the button below will work.
Ready. Click the button, then pick “PineVoice” in the Bluetooth popup.

After WiFi joins, one manual step remains — pair the speaker in Home Assistant: Settings → Devices & services → Add Wyoming Protocol, host = the speaker’s IP, port 10700. Whisper, Piper, openWakeWord and the Assist pipeline are wired up automatically when Pine installs. Wake word: “Hey Jarvis.” Ask node things like “what’s the block height?”, “how many peers?”, “is the node synced?” or “what’s my lightning balance?” — and when a Claude API key is set on the node, anything else gets answered by Claude. New mesh messages are announced on the speaker too.

Troubleshooting: if it hears you (LED reacts) but answers are silent, unplug and replug the speaker — an interrupted answer can wedge its audio output until it reboots.

health_check: type: tcp endpoint: localhost:443 interval: 30s timeout: 5s retries: 5 start_period: 10s interfaces: main: name: Pine description: Connect your speaker to WiFi and check the voice assistant type: ui port: 10380 protocol: http path: / metadata: author: Archipelago icon: /assets/img/app-icons/pine.svg website: https://github.com/rhasspy/wyoming repo: https://github.com/rhasspy/wyoming license: MIT category: home launch: open_in_new_tab: true tags: - home - voice - assistant - privacy