docs(spotify): expand feature page with tool reference, Free/Premium matrix, troubleshooting (#15135)

The initial Spotify docs page shipped in #15130 was a setup guide. This
expands it into a full feature reference:

- Per-tool parameter table for all 9 tools, extracted from the real
  schemas in tools/spotify_tool.py (actions, required/optional args,
  premium gating).
- Free vs Premium feature matrix — which actions work on which tier,
  so Free users don't assume Spotify tools are useless to them.
- Active-device prerequisite called out at the top; this is the #1
  cause of '403 no active device' reports for every Spotify
  integration.
- SSH / headless section explaining that browser auto-open is skipped
  when SSH_CLIENT/SSH_TTY is set, and how to tunnel the callback port.
- Token lifecycle: refresh on 401, persistence across restarts, how
  to revoke server-side via spotify.com/account/apps.
- Example prompt list so users know what to ask the agent.
- Troubleshooting expanded: no-active-device, Premium-required, 204
  now_playing, INVALID_CLIENT, 429, 401 refresh-revoked, wizard not
  opening browser.
- 'Where things live' table mapping auth.json / .env / Spotify app.

Verified with 'node scripts/prebuild.mjs && npx docusaurus build'
— page compiles, no new warnings.
This commit is contained in:
Teknium 2026-04-24 05:38:02 -07:00 committed by GitHub
parent fe9d9a26d8
commit 9be17bb84f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,13 +1,14 @@
# Spotify # Spotify
Hermes can control Spotify directly — playback, queue, search, playlists, saved tracks/albums, and listening history — using Spotify's official Web API with PKCE OAuth. Hermes can control Spotify directly — playback, queue, search, playlists, saved tracks/albums, and listening history — using Spotify's official Web API with PKCE OAuth. Tokens are stored in `~/.hermes/auth.json` and refreshed automatically on 401; you only log in once per machine.
Unlike most Hermes integrations, Spotify requires every user to register their own lightweight developer app. Spotify does not let third parties ship a public OAuth app that anyone can use. The whole thing takes about two minutes. Unlike Hermes' built-in OAuth integrations (Google, GitHub Copilot, Codex), Spotify requires every user to register their own lightweight developer app. Spotify does not let third parties ship a public OAuth app that anyone can use. It takes about two minutes and `hermes auth spotify` walks you through it.
## Prerequisites ## Prerequisites
- A Spotify account (Free works for most tools; **playback control requires Premium**) - A Spotify account. **Free** works for search, playlist, library, and activity tools. **Premium** is required for playback control (play, pause, skip, seek, volume, queue add, transfer).
- Hermes Agent installed and running - Hermes Agent installed and running.
- For playback tools: an **active Spotify Connect device** — the Spotify app must be open on at least one device (phone, desktop, web player, speaker) so the Web API has something to control. If nothing is active you'll get a `403 Forbidden` with a "no active device" message; open Spotify on any device and retry.
## Setup ## Setup
@ -17,7 +18,7 @@ Unlike most Hermes integrations, Spotify requires every user to register their o
hermes tools hermes tools
``` ```
Scroll to `🎵 Spotify`, press space to toggle it on, then `s` to save. 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.
### 2. Run the login wizard ### 2. Run the login wizard
@ -25,18 +26,19 @@ Scroll to `🎵 Spotify`, press space to toggle it on, then `s` to save.
hermes auth spotify hermes auth spotify
``` ```
If you don't have a Spotify app yet, Hermes walks you through creating one: If no `HERMES_SPOTIFY_CLIENT_ID` is set, Hermes walks you through the app registration inline:
1. Opens the Spotify developer dashboard in your browser 1. Opens `https://developer.spotify.com/dashboard` in your browser
2. Tells you exactly what values to paste into the Spotify form 2. Prints the exact values to paste into Spotify's "Create app" form
3. Prompts you for the `Client ID` you get back 3. Prompts you for the Client ID you get back
4. Saves it to `~/.hermes/.env` and continues straight into the OAuth flow 4. Saves it to `~/.hermes/.env` so future runs skip this step
5. Continues straight into the OAuth consent flow
After the Spotify consent page, tokens are saved under `providers.spotify` in `~/.hermes/auth.json` and the integration is live. After you approve, tokens are written under `providers.spotify` in `~/.hermes/auth.json`. The active inference provider is NOT changed — Spotify auth is independent of your LLM provider.
### Creating the Spotify app (what the wizard asks for) ### Creating the Spotify app (what the wizard asks for)
When you land on the dashboard, click **Create app** and fill in: When the dashboard opens, click **Create app** and fill in:
| Field | Value | | Field | Value |
|-------|-------| |-------|-------|
@ -44,9 +46,13 @@ When you land on the dashboard, click **Create app** and fill in:
| App description | anything (e.g. `personal Hermes integration`) | | App description | anything (e.g. `personal Hermes integration`) |
| Website | leave blank | | Website | leave blank |
| Redirect URI | `http://127.0.0.1:43827/spotify/callback` | | Redirect URI | `http://127.0.0.1:43827/spotify/callback` |
| Which API/SDKs? | **Web API** | | Which API/SDKs? | check **Web API** |
Agree to the terms, click **Save**. On the next screen click **Settings** → copy the **Client ID**. That's the only value Hermes needs (no client secret — PKCE doesn't use one). Agree to the terms and click **Save**. On the next page click **Settings** → copy the **Client ID** and paste it into the Hermes prompt. That's the only value Hermes needs — PKCE doesn't use a client secret.
### Running over SSH / in a headless environment
If `SSH_CLIENT` or `SSH_TTY` is set, Hermes skips the automatic browser open during both the wizard and the OAuth step. Copy the dashboard URL and the authorization URL Hermes prints, open them in a browser on your local machine, and proceed normally — the local HTTP listener still runs on the remote host on port 43827. If you need to reach it through an SSH tunnel, forward that port: `ssh -L 43827:127.0.0.1:43827 remote`.
## Verify ## Verify
@ -54,25 +60,101 @@ Agree to the terms, click **Save**. On the next screen click **Settings** → co
hermes auth status spotify hermes auth status spotify
``` ```
Shows whether tokens are present and when the access token expires. Hermes automatically refreshes on 401. Shows whether tokens are present and when the access token expires. Refresh is automatic: when any Spotify API call returns 401, the client exchanges the refresh token and retries once. Refresh tokens persist across Hermes restarts, so you only re-auth if you revoke the app in your Spotify account settings or run `hermes auth logout spotify`.
## Using it ## Using it
Once logged in, the agent has access to 9 Spotify tools: Once logged in, the agent has access to 9 Spotify tools. You talk to the agent naturally — it picks the right tool and action.
| Tool | Actions | ```
|------|---------| > play some miles davis
| `spotify_playback` | play, pause, skip, seek, volume, now playing, playback state | > what am I listening to
| `spotify_devices` | list devices, transfer playback | > add this track to my Late Night Jazz playlist
| `spotify_queue` | inspect queue, add tracks to queue | > skip to the next song
| `spotify_search` | search tracks, albums, artists, playlists | > make a new playlist called "Focus 2026" and add the last three songs I played
| `spotify_playlists` | list, get, create, update, add/remove tracks | > which of my saved albums are by Radiohead
| `spotify_albums` | get album, list album tracks | > search for acoustic covers of Blackbird
| `spotify_saved_tracks` | list, save, remove | > transfer playback to my kitchen speaker
| `spotify_saved_albums` | list, save, remove | ```
| `spotify_activity` | recently played, now playing |
The agent picks the right tool automatically. Ask it to "play some Miles Davis," "what am I listening to," "add the current track to my starred playlist," etc. ### Tool reference
All playback-mutating actions accept an optional `device_id` to target a specific device. If omitted, Spotify uses the currently active device.
#### `spotify_playback`
Control and inspect playback.
| Action | Purpose | Premium? |
|--------|---------|----------|
| `get_state` | Full playback state (track, device, progress, shuffle/repeat) | No |
| `get_currently_playing` | Just the current track | No |
| `play` | Start/resume playback. Optional: `context_uri`, `uris`, `offset`, `position_ms` | Yes |
| `pause` | Pause playback | Yes |
| `next` / `previous` | Skip track | Yes |
| `seek` | Jump to `position_ms` | Yes |
| `set_repeat` | `state` = `track` / `context` / `off` | Yes |
| `set_shuffle` | `state` = `true` / `false` | Yes |
| `set_volume` | `volume_percent` = 0-100 | Yes |
#### `spotify_devices`
| Action | Purpose |
|--------|---------|
| `list` | Every Spotify Connect device visible to your account |
| `transfer` | Move playback to `device_id`. Optional `play: true` starts playback on transfer |
#### `spotify_queue`
| Action | Purpose | Premium? |
|--------|---------|----------|
| `get` | Currently queued tracks | No |
| `add` | Append `uri` to the queue | Yes |
#### `spotify_search`
Search the catalog. `query` is required. Optional: `types` (array of `track` / `album` / `artist` / `playlist` / `show` / `episode`), `limit`, `offset`, `market`.
#### `spotify_playlists`
| Action | Purpose | Required args |
|--------|---------|---------------|
| `list` | User's playlists | — |
| `get` | One playlist + tracks | `playlist_id` |
| `create` | New playlist | `name` (+ optional `description`, `public`, `collaborative`) |
| `add_items` | Add tracks | `playlist_id`, `uris` (optional `position`) |
| `remove_items` | Remove tracks | `playlist_id`, `uris` (+ optional `snapshot_id`) |
| `update_details` | Rename / edit | `playlist_id` + any of `name`, `description`, `public`, `collaborative` |
#### `spotify_albums`
| Action | Purpose | Required args |
|--------|---------|---------------|
| `get` | Album metadata | `album_id` |
| `tracks` | Album track list | `album_id` |
#### `spotify_saved_tracks` / `spotify_saved_albums`
| Action | Purpose |
|--------|---------|
| `list` | Paginated library listing |
| `save` | Add `ids` / `uris` to library |
| `remove` | Remove `ids` / `uris` from library |
#### `spotify_activity`
| Action | Purpose | Premium? |
|--------|---------|----------|
| `now_playing` | Currently playing (returns empty on 204 — see below) | No |
| `recently_played` | Last played tracks. Optional `limit`, `before`, `after` (Unix ms) | No |
### Feature matrix: Free vs Premium
Read-only tools work on Free accounts. Anything that mutates playback or the queue requires Premium.
| Works on Free | Premium required |
|---------------|------------------|
| `spotify_search` (all) | `spotify_playback` — play, pause, next, previous, seek, set_repeat, set_shuffle, set_volume |
| `spotify_playback` — get_state, get_currently_playing | `spotify_queue` — add |
| `spotify_devices` — list | `spotify_devices` — transfer |
| `spotify_queue` — get | |
| `spotify_playlists` (all) | |
| `spotify_albums` (all) | |
| `spotify_saved_tracks` (all) | |
| `spotify_saved_albums` (all) | |
| `spotify_activity` (all) | |
## Sign out ## Sign out
@ -80,27 +162,35 @@ The agent picks the right tool automatically. Ask it to "play some Miles Davis,"
hermes auth logout spotify hermes auth logout spotify
``` ```
Removes tokens from `~/.hermes/auth.json`. To also clear the app config, delete `HERMES_SPOTIFY_CLIENT_ID` (and optionally `HERMES_SPOTIFY_REDIRECT_URI`) from `~/.hermes/.env`. Removes tokens from `~/.hermes/auth.json`. To also clear the app config, delete `HERMES_SPOTIFY_CLIENT_ID` (and `HERMES_SPOTIFY_REDIRECT_URI` if you set it) from `~/.hermes/.env`, or run the wizard again.
To revoke the app on Spotify's side, visit [Apps connected to your account](https://www.spotify.com/account/apps/) and click **REMOVE ACCESS**.
## Troubleshooting ## Troubleshooting
**`403 Forbidden` on playback endpoints** — Spotify requires Premium for `play`, `pause`, `skip`, and volume control. Search, playlists, and library reads work on Free. **`403 Forbidden — Player command failed: No active device found`** — You need Spotify running on at least one device. Open the Spotify app on your phone, desktop, or web player, start any track for a second to register it, and retry. `spotify_devices list` shows what's currently visible.
**`204 No Content` on `now_playing`** — nothing is currently playing; expected behavior, not an error. **`403 Forbidden — Premium required`** — You're on a Free account trying to use a playback-mutating action. See the feature matrix above.
**`INVALID_CLIENT: Invalid redirect URI`** — the redirect URI registered in your Spotify app doesn't match what Hermes is using. Default is `http://127.0.0.1:43827/spotify/callback`. If you picked something else, set `HERMES_SPOTIFY_REDIRECT_URI` in `~/.hermes/.env` to match. **`204 No Content` on `now_playing`** — nothing is currently playing on any device. This is Spotify's normal response, not an error; Hermes surfaces it as an explanatory empty result.
**`429 Too Many Requests`** — Spotify rate limit. Hermes surfaces this as a friendly error; wait a minute and retry. **`INVALID_CLIENT: Invalid redirect URI`** — the redirect URI in your Spotify app settings doesn't match what Hermes is using. The default is `http://127.0.0.1:43827/spotify/callback`. Either add that to your app's allowed redirect URIs, or set `HERMES_SPOTIFY_REDIRECT_URI` in `~/.hermes/.env` to whatever you registered.
**`429 Too Many Requests`** — Spotify's rate limit. Hermes returns a friendly error; wait a minute and retry. If this persists, you're probably running a tight loop in a script — Spotify's quota resets roughly every 30 seconds.
**`401 Unauthorized` keeps coming back** — Your refresh token was revoked (usually because you removed the app from your account, or the app was deleted). Run `hermes auth spotify` again.
**Wizard doesn't open the browser** — If you're over SSH or in a container without a display, Hermes detects it and skips the auto-open. Copy the dashboard URL it prints and open it manually.
## Advanced: custom scopes ## Advanced: custom scopes
By default Hermes requests the scopes needed for every shipped tool. To override: By default Hermes requests the scopes needed for every shipped tool. Override if you want to restrict access:
```bash ```bash
hermes auth spotify --scope "user-read-playback-state user-modify-playback-state playlist-read-private" hermes auth spotify --scope "user-read-playback-state user-modify-playback-state playlist-read-private"
``` ```
See Spotify's [scope reference](https://developer.spotify.com/documentation/web-api/concepts/scopes) for available values. Scope reference: [Spotify Web API scopes](https://developer.spotify.com/documentation/web-api/concepts/scopes). If you request fewer scopes than a tool needs, that tool's calls will fail with 403.
## Advanced: custom client ID / redirect URI ## Advanced: custom client ID / redirect URI
@ -115,4 +205,12 @@ HERMES_SPOTIFY_CLIENT_ID=<your_id>
HERMES_SPOTIFY_REDIRECT_URI=http://localhost:3000/callback HERMES_SPOTIFY_REDIRECT_URI=http://localhost:3000/callback
``` ```
The redirect URI must be allow-listed in your Spotify app's settings. The redirect URI must be allow-listed in your Spotify app's settings. The default works for almost everyone — only change it if port 43827 is taken.
## Where things live
| File | Contents |
|------|----------|
| `~/.hermes/auth.json``providers.spotify` | access token, refresh token, expiry, scope, redirect URI |
| `~/.hermes/.env` | `HERMES_SPOTIFY_CLIENT_ID`, optional `HERMES_SPOTIFY_REDIRECT_URI` |
| Spotify app | owned by you at [developer.spotify.com/dashboard](https://developer.spotify.com/dashboard); contains the Client ID and the redirect URI allow-list |