Reyna CLI
On-demand CLI façade for Reyna family MCP services and LAN devices. The goal is to avoid keeping every MCP server/tool schema loaded in Hermes memory while still letting Hermes call capabilities through terminal when needed.
Phase 2 scope
- Devices parent command: Non-Tactility local devices remain under
reyna-cli devices; ESP32 boards use the dedicatedreyna-cli tactilitycommand group.reyna-cli devices screen ...(ESP32 screen)reyna-cli devices laptop ...(personal laptop MCP screen)reyna-cli devices computer ...(this computer's desktop companion client)reyna-cli devices iphone ...(iPhone app)
- Tactility boards: mDNS-first discovery with reserved-IP fallback, plus direct web API access for sysinfo, apps, app installation/run, and filesystem operations.
- Immich: On-demand MCP bridge at
http://127.0.0.1:8626/mcp. - MongoDB: On-demand MCP bridge at
http://127.0.0.1:8630/mcp. - Top-level aliases:
reyna-cli screen,reyna-cli laptop, andreyna-cli iphonestill work for compatibility.
Install / run
uv sync
uv run reyna-cli doctor
Signed Python launcher (macOS permissions)
The manually built, signed Reyna CLI.app owns the macOS privacy identity. Use the signed wrapper to launch the current Python CLI through that app:
# Optional: use a different active checkout or interpreter without rebuilding the app.
cat > ~/.reyna-cli.env <<'EOF'
REYNA_CLI_DIR=/Users/adolforeyna/Projects/platform/reyna-cli
REYNA_CLI_PYTHON=/Users/adolforeyna/Projects/platform/reyna-cli/.venv/bin/python
EOF
uv run reyna-cli signed doctor
uv run reyna-cli signed local-services speech transcribe-file ./sample.wav --json
The signed launcher reads ~/.reyna-cli.env, then ~/.config/reyna-cli/env; REYNA_CLI_DIR and REYNA_CLI_PYTHON environment variables override those values. Python-only edits take effect on the next signed run—do not rebuild or re-sign the app for those edits. Changes to Swift sources, Info.plist, or app signing require a new manual signed Xcode build before they can be used by signed.
Device discovery
uv run reyna-cli devices list --json
uv run reyna-cli devices ping esp32_screen --json
uv run reyna-cli devices tools esp32_screen --json
uv run reyna-cli devices describe esp32_screen --for-hermes
# Tactility fleet discovery; offline boards remain visible in the JSON report
uv run reyna-cli tactility discover --json
uv run reyna-cli tactility sysinfo kidsos1 --json
uv run reyna-cli tactility apps kidsos1 --json
uv run reyna-cli tactility tools Grace --json
uv run reyna-cli tactility describe Grace --json
uv run reyna-cli tactility call Grace get_screenshot --args '{}' --json
uv run reyna-cli tactility call Grace draw_color_bmp --args '{"bmp_base64":"...","x":0,"y":0}' --json
uv run reyna-cli tactility call Grace play_tone --args '{"frequency":440,"duration_ms":500,"volume":40}' --json
uv run reyna-cli tactility call Grace get_sensors --args '{}' --json
uv run reyna-cli tactility install kidsos1 ./build/my.app --json
uv run reyna-cli tactility run kidsos1 one.tactility.myapp --json
uv run reyna-cli tactility report kidsos1 --json
uv run reyna-cli tactility screen clear kidsos1 --width 320 --height 240 --json
uv run reyna-cli tactility screen text kidsos1 "Grace\\nReady" --json
uv run reyna-cli tactility screen text kidsos1 "Layer intentionally" --no-clear-first --json
uv run reyna-cli tactility fs list kidsos1 --path /sdcard --json
uv run reyna-cli tactility fs upload kidsos1 ./manifest.json /sdcard/manifest.json --json
Generic MCP calls
uv run reyna-cli devices call esp32_screen draw_text --args '{"text":"Hello","x":10,"y":20,"size":2}' --json
ESP32 screen, laptop screen, this computer & iPhone
uv run reyna-cli devices screen text "Dinner is ready"
uv run reyna-cli devices laptop text "Hermes is online" --json
uv run reyna-cli devices laptop battery --json
uv run reyna-cli devices laptop sensors --json
uv run reyna-cli devices computer service-status --json
uv run reyna-cli devices computer text "Hermes is online here" --json
uv run reyna-cli devices iphone battery --json
This computer desktop client service
The local desktop companion client runs /home/adolforeyna/Projects/Screen/desktop_client/client.py in the GUI session with WAYLAND_DISPLAY=wayland-0 and XDG_RUNTIME_DIR=/run/user/1000.
uv run reyna-cli computer service-install --json
uv run reyna-cli computer service-start --json
uv run reyna-cli computer service-status --json
uv run reyna-cli computer service-restart --json
uv run reyna-cli computer service-logs --lines 80
Immich
uv run reyna-cli immich stats
uv run reyna-cli immich albums
uv run reyna-cli immich search "sunset" --limit 5
uv run reyna-cli immich tools
MongoDB
uv run reyna-cli mongo dbs
uv run reyna-cli mongo collections my_db
uv run reyna-cli mongo count my_db my_coll --filter '{"status":"active"}'
uv run reyna-cli mongo find my_db my_coll --limit 5
uv run reyna-cli mongo aggregate my_db my_coll --pipeline '[{"$match":{}}]'
Local Thunderbird email (read-only)
The email command searches the locally synced Thunderbird MBOX files directly. It is read-only: it does not send, delete, move, label, or modify mail.
uv run reyna-cli email doctor --json
uv run reyna-cli email search "whirlpool fridge warranty" --limit 5 --json
uv run reyna-cli email find-receipts "Whirlpool" --json
uv run reyna-cli email latest --limit 10 --json
uv run reyna-cli email show <message-id> --body --json
By default it uses the local Thunderbird profile at ~/snap/thunderbird/common/.thunderbird/tjug9cp5.default and the Gmail INBOX MBOX. Override with REYNA_THUNDERBIRD_PROFILE or REYNA_THUNDERBIRD_INBOX when testing or using a different profile.
Mac mini
The macmini command reads the existing Hermes mcp_servers.macmini HTTP URL and Authorization header from ~/.hermes/config.yaml, so credentials stay in the Hermes profile config instead of being duplicated here.
uv run reyna-cli macmini ping --json
uv run reyna-cli macmini tools --json
uv run reyna-cli macmini call notes_list --args '{"limit":5}' --json
uv run reyna-cli macmini calendar calendars --json
uv run reyna-cli macmini calendar events 2026-06-11T00:00:00 2026-06-12T00:00:00 --json
uv run reyna-cli macmini calendar create "Dentist" 2026-06-15T09:00:00 2026-06-15T10:00:00 --notes "Bring insurance card"
uv run reyna-cli macmini contacts search Adolfo --json
uv run reyna-cli macmini notes list --query family --json
uv run reyna-cli macmini reminders lists --json
TP-Link Deco
The deco command talks directly to the router with tplinkrouterc6u; it does not use the Mac mini MCP server. Configure DECO_HOST, DECO_USERNAME, DECO_PASSWORD, DECO_VERIFY_SSL, and DECO_TIMEOUT in ~/.hermes/.env or the process environment. DECO_HOST defaults to the Linux default gateway when omitted.
uv run reyna-cli deco config --json
uv run reyna-cli deco overview --json
uv run reyna-cli deco clients --json
uv run reyna-cli deco firmware --json
uv run reyna-cli deco ipv4 --json
# Backward-compatible alias; also direct, not MCP:
uv run reyna-cli macmini deco clients --json
Browser web interface
reyna-cli web runs a FastAPI/uvicorn browser UI that can execute Reyna CLI commands from a browser. The web app uses Authentik OIDC by default against auth.reynafamily.com.
Create an Authentik OAuth2/OpenID provider/application for the web app and add a redirect URI that matches where you will browse to the server, for example:
https://reyna-cli.reynafamily.com/auth/callback
Configure the server with environment variables (for example in ~/.hermes/.env or your service manager):
REYNA_WEB_SESSION_SECRET='generate-a-long-random-string'
REYNA_WEB_AUTH_CLIENT_ID='authentik-client-id'
REYNA_WEB_AUTH_CLIENT_SECRET='authentik-client-secret'
REYNA_WEB_AUTH_ISSUER='https://auth.reynafamily.com/application/o/reyna-cli-web/'
REYNA_WEB_PUBLIC_URL='https://reyna-cli.reynafamily.com'
Run locally:
uv run reyna-cli web --host 127.0.0.1 --port 8765
For a trusted LAN-only development session, bypass OIDC with:
REYNA_WEB_DEV_AUTH=1 uv run reyna-cli web --host 127.0.0.1 --port 8765
Tests
uv run pytest -q