feat(spotify): wire setup wizard into 'hermes tools' + document cron usage (#15180)

A — 'hermes tools' activation now runs the full Spotify wizard.

Previously a user had to (1) toggle the Spotify toolset on in 'hermes
tools' AND (2) separately run 'hermes auth spotify' to actually use
it. The second step was a discovery gap — the docs mentioned it but
nothing in the TUI pointed users there.

Now toggling Spotify on calls login_spotify_command as a post_setup
hook. If the user has no client_id yet, the interactive wizard walks
them through Spotify app creation; if they do, it skips straight to
PKCE. Either way, one 'hermes tools' pass leaves Spotify toggled on
AND authenticated. SystemExit from the wizard (user abort) leaves the
toolset enabled and prints a 'run: hermes auth spotify' hint — it
does NOT fail the toolset toggle.

Dropped the TOOL_CATEGORIES env_vars list for Spotify. The wizard
handles HERMES_SPOTIFY_CLIENT_ID persistence itself, and asking users
to type env var names before the wizard fires was UX-backwards — the
point of the wizard is that they don't HAVE a client_id yet.

B — Docs page now covers cron + Spotify.

New 'Scheduling: Spotify + cron' section with two working examples
(morning playlist, wind-down pause) using the real 'hermes cron add'
CLI surface (verified via 'cron add --help'). Covers the active-device
gotcha, Premium gating, memory isolation, and links to the cron docs.

Also fixed a stale '9 Spotify tools' reference in the setup copy —
we consolidated to 7 tools in #15154.

Validation:
- scripts/run_tests.sh tests/hermes_cli/test_tools_config.py
    tests/hermes_cli/test_spotify_auth.py
    tests/tools/test_spotify_client.py
  → 54 passed
- website: node scripts/prebuild.mjs && npx docusaurus build
  → SUCCESS, no new warnings
This commit is contained in:
Teknium 2026-04-24 07:24:28 -07:00 committed by GitHub
parent 591aa159aa
commit 1840c6a57d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 87 additions and 10 deletions

View file

@ -368,13 +368,9 @@ TOOL_CATEGORIES = {
"providers": [ "providers": [
{ {
"name": "Spotify Web API", "name": "Spotify Web API",
"tag": "PKCE OAuth — run `hermes auth spotify` after this", "tag": "PKCE OAuth — opens the setup wizard",
"env_vars": [ "env_vars": [],
{"key": "HERMES_SPOTIFY_CLIENT_ID", "prompt": "Spotify app client_id", "post_setup": "spotify",
"url": "https://developer.spotify.com/dashboard"},
{"key": "HERMES_SPOTIFY_REDIRECT_URI", "prompt": "Redirect URI (must be allow-listed in your Spotify app)",
"default": "http://127.0.0.1:43827/spotify/callback"},
],
}, },
], ],
}, },
@ -478,6 +474,35 @@ def _run_post_setup(post_setup_key: str):
_print_warning(" kittentts install timed out (>5min)") _print_warning(" kittentts install timed out (>5min)")
_print_info(f" Run manually: python -m pip install -U '{wheel_url}' soundfile") _print_info(f" Run manually: python -m pip install -U '{wheel_url}' soundfile")
elif post_setup_key == "spotify":
# Run the full `hermes auth spotify` flow — if the user has no
# client_id yet, this drops them into the interactive wizard
# (opens the Spotify dashboard, prompts for client_id, persists
# to ~/.hermes/.env), then continues straight into PKCE. If they
# already have an app, it skips the wizard and just does OAuth.
from types import SimpleNamespace
try:
from hermes_cli.auth import login_spotify_command
except Exception as exc:
_print_warning(f" Could not load Spotify auth: {exc}")
_print_info(" Run manually: hermes auth spotify")
return
_print_info(" Starting Spotify login...")
try:
login_spotify_command(SimpleNamespace(
client_id=None, redirect_uri=None, scope=None,
no_browser=False, timeout=None,
))
_print_success(" Spotify authenticated")
except SystemExit as exc:
# User aborted the wizard, or OAuth failed — don't fail the
# toolset enable; they can retry with `hermes auth spotify`.
_print_warning(f" Spotify login did not complete: {exc}")
_print_info(" Run later: hermes auth spotify")
except Exception as exc:
_print_warning(f" Spotify login failed: {exc}")
_print_info(" Run manually: hermes auth spotify")
elif post_setup_key == "rl_training": elif post_setup_key == "rl_training":
try: try:
__import__("tinker_atropos") __import__("tinker_atropos")

View file

@ -12,20 +12,36 @@ Unlike Hermes' built-in OAuth integrations (Google, GitHub Copilot, Codex), Spot
## Setup ## Setup
### 1. Enable the toolset ### One-shot: `hermes tools`
The fastest path. Run:
```bash ```bash
hermes tools hermes tools
``` ```
Scroll to `🎵 Spotify`, press space to toggle it on, then `s` to save. The 9 Spotify tools only appear in the agent's toolset after this — they're off by default so users who don't want them don't ship extra tool schemas on every API call. Scroll to `🎵 Spotify`, press space to toggle it on, then `s` to save. Hermes drops you straight into the OAuth flow — if you don't have a Spotify app yet, it walks you through creating one inline. Once you finish, the toolset is enabled AND authenticated in one pass.
### 2. Run the login wizard If you prefer to do the steps separately (or you're re-authing later), use the two-step flow below.
### Two-step flow
#### 1. Enable the toolset
```bash
hermes tools
```
Toggle `🎵 Spotify` on, save, and when the inline wizard opens, dismiss it (Ctrl+C). The toolset stays on; only the auth step is deferred.
#### 2. Run the login wizard
```bash ```bash
hermes auth spotify hermes auth spotify
``` ```
The 7 Spotify tools only appear in the agent's toolset after step 1 — they're off by default so users who don't want them don't ship extra tool schemas on every API call.
If no `HERMES_SPOTIFY_CLIENT_ID` is set, Hermes walks you through the app registration inline: If no `HERMES_SPOTIFY_CLIENT_ID` is set, Hermes walks you through the app registration inline:
1. Opens `https://developer.spotify.com/dashboard` in your browser 1. Opens `https://developer.spotify.com/dashboard` in your browser
@ -153,6 +169,42 @@ Read-only tools work on Free accounts. Anything that mutates playback or the que
| `spotify_albums` (all) | | | `spotify_albums` (all) | |
| `spotify_library` (all) | | | `spotify_library` (all) | |
## Scheduling: Spotify + cron
Because Spotify tools are regular Hermes tools, a cron job running in a Hermes session can trigger playback on any schedule. No new code needed.
### Morning wake-up playlist
```bash
hermes cron add \
--name "morning-commute" \
"0 7 * * 1-5" \
"Transfer playback to my kitchen speaker and start my 'Morning Commute' playlist. Volume to 40. Shuffle on."
```
What happens at 7am every weekday:
1. Cron spins up a headless Hermes session.
2. Agent reads the prompt, calls `spotify_devices list` to find "kitchen speaker" by name, then `spotify_devices transfer``spotify_playback set_volume``spotify_playback set_shuffle``spotify_search` + `spotify_playback play`.
3. Music starts on the target speaker. Total cost: one session, a few tool calls, no human input.
### Wind-down at night
```bash
hermes cron add \
--name "wind-down" \
"30 22 * * *" \
"Pause Spotify. Then set volume to 20 so it's quiet when I start it again tomorrow."
```
### Gotchas
- **An active device must exist when the cron fires.** If no Spotify client is running (phone/desktop/Connect speaker), playback actions return `403 no active device`. For morning playlists, the trick is to target a device that's always on (Sonos, Echo, a smart speaker) rather than your phone.
- **Premium required for anything that mutates playback** — play, pause, skip, volume, transfer. Read-only cron jobs (scheduled "email me my recently played tracks") work fine on Free.
- **The cron agent inherits your active toolsets.** Spotify must be enabled in `hermes tools` for the cron session to see the Spotify tools.
- **Cron jobs run with `skip_memory=True`** so they don't write to your memory store.
Full cron reference: [Cron Jobs](./cron).
## Sign out ## Sign out
```bash ```bash