From 1840c6a57d346ec402bfa7c0ffc758fa22236972 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 24 Apr 2026 07:24:28 -0700 Subject: [PATCH] feat(spotify): wire setup wizard into 'hermes tools' + document cron usage (#15180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- hermes_cli/tools_config.py | 39 +++++++++++--- website/docs/user-guide/features/spotify.md | 58 +++++++++++++++++++-- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/hermes_cli/tools_config.py b/hermes_cli/tools_config.py index 09fc8ceec..32645aea3 100644 --- a/hermes_cli/tools_config.py +++ b/hermes_cli/tools_config.py @@ -368,13 +368,9 @@ TOOL_CATEGORIES = { "providers": [ { "name": "Spotify Web API", - "tag": "PKCE OAuth — run `hermes auth spotify` after this", - "env_vars": [ - {"key": "HERMES_SPOTIFY_CLIENT_ID", "prompt": "Spotify app client_id", - "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"}, - ], + "tag": "PKCE OAuth — opens the setup wizard", + "env_vars": [], + "post_setup": "spotify", }, ], }, @@ -478,6 +474,35 @@ def _run_post_setup(post_setup_key: str): _print_warning(" kittentts install timed out (>5min)") _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": try: __import__("tinker_atropos") diff --git a/website/docs/user-guide/features/spotify.md b/website/docs/user-guide/features/spotify.md index de97ca3a1..bf9d652b3 100644 --- a/website/docs/user-guide/features/spotify.md +++ b/website/docs/user-guide/features/spotify.md @@ -12,20 +12,36 @@ Unlike Hermes' built-in OAuth integrations (Google, GitHub Copilot, Codex), Spot ## Setup -### 1. Enable the toolset +### One-shot: `hermes tools` + +The fastest path. Run: ```bash 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 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: 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_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 ```bash