2026-06-11 15:05:31 +00:00

Smart Assistant

Voice assistant on a Raspberry Pi talking to the OpenAI Realtime API via an ASP.NET backend deployed on Coolify.

See docs/superpowers/specs/2026-06-11-smart-assistant-design.md for the full design and docs/superpowers/plans/2026-06-11-smart-assistant-backend-foundation.md for the Plan 1 implementation steps that produced this code.

Repo layout

  • backend/ — ASP.NET 9 backend (Identity, Devices, Pairing, Install).
  • backend.tests/ — xUnit integration + unit tests via WebApplicationFactory.
  • client/ — Python client. Plan 1 ships placeholders only; the full wakeword + Realtime client lands in Plan 3.
  • Dockerfile + docker-compose.yml — multi-stage build; produces one image with the published ASP.NET app + a bundled client.tar.gz in wwwroot/client.tar.gz.
  • deploy.json — Coolify config (gitignored; contains the OpenAI key).
  • docs/superpowers/ — specs and plans.

Local development

dotnet test                              # all backend tests
dotnet run --project backend             # starts on http://localhost:5000

Hit http://localhost:5000/health to verify it's up.

Smoke test against a live deploy

The full pairing flow can be exercised with curl — no UI needed yet.

DOMAIN="https://assistant.volcanic.tes.gd"          # or your domain
COOKIE=$(mktemp)

# Register the first user (becomes Admin automatically) and sign in
curl -sf -c "$COOKIE" -X POST "$DOMAIN/api/auth/register" \
  -H 'content-type: application/json' \
  -d '{"email":"you@example.com","password":"Passw0rd!"}'
curl -sf -c "$COOKIE" -b "$COOKIE" -X POST "$DOMAIN/api/auth/login" \
  -H 'content-type: application/json' \
  -d '{"email":"you@example.com","password":"Passw0rd!"}'

# Generate a pairing code (auth required)
CODE=$(curl -sf -c "$COOKIE" -b "$COOKIE" -X POST "$DOMAIN/api/pair-code" \
  -H 'content-type: application/json' \
  -d '{"name":"kitchen"}' \
  | python3 -c 'import sys,json; print(json.load(sys.stdin)["code"])')
echo "code=$CODE"

# Pair as a device (public endpoint) and capture the token
curl -sf -X POST "$DOMAIN/api/pair" \
  -H 'content-type: application/json' \
  -d "{\"code\":\"$CODE\",\"hostname\":\"smoke\",\"client_version\":\"0.1\"}" \
  | python3 -m json.tool

# Verify the install script and client bundle are served
curl -sf "$DOMAIN/install.sh" | head -5
curl -sIf "$DOMAIN/client.tar.gz"

Expected: {"ok":true} on /health, JSON with device_id/device_token/backend_ws from /api/pair, the bash shebang from /install.sh, and a 200 OK with Content-Type: application/gzip for the bundle.

Plan 1 ships a placeholder Python bundle — running the bundled client.main will exit with the placeholder message. Plan 3 replaces it with the real wakeword + Realtime client.

Deploying

Use the Coolify v4 API. The deploy.json file (gitignored) carries the project + server UUIDs and the OpenAI key.

APP=$(python3 -c "import json; print(json.load(open('deploy.json'))['app']['uuid'])")
curl -sf -X POST "$COOLIFY_URL/api/v1/deploy?uuid=$APP" \
  -H "Authorization: Bearer $COOLIFY_KEY"

Fire-and-forget; the API returns a deployment_uuid immediately. Don't poll (per the global Coolify rule in CLAUDE.md).

What's next

  • Plan 2 — backend device hub + OpenAI Realtime relay + tools registry (the end_session, get_current_time, set_volume tools the spec describes).
  • Plan 3 — full Python client on the Pi (wakeword, VAD, audio plumbing, state machine, install + pair CLIs).
  • Plan 4 — React management UI for the admin dashboard and conversation history viewer.
S
Description
No description provided
Readme 2.9 MiB
Languages
C# 73.2%
Python 25.3%
Shell 1%
Dockerfile 0.5%