Skip to content

feat(spotify): add native Spotify tools with PKCE auth#15096

Closed
dlkakbs wants to merge 1 commit into
NousResearch:mainfrom
dlkakbs:feat/native-spotify-tools
Closed

feat(spotify): add native Spotify tools with PKCE auth#15096
dlkakbs wants to merge 1 commit into
NousResearch:mainfrom
dlkakbs:feat/native-spotify-tools

Conversation

@dlkakbs

@dlkakbs dlkakbs commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a native Spotify integration to Hermes as a first-class tool surface, using Spotify OAuth PKCE and Hermes' existing auth and credential lifecycle.

This PR does not add an MCP wrapper or a separate secret storage mechanism. Instead, it integrates Spotify into Hermes' current auth model (~/.hermes/auth.json) and exposes Spotify through native Hermes tools, toolsets, and CLI auth commands.

The implementation adds 9 native Spotify Hermes tools covering roughly 31 user-facing actions across playback, devices, queue, search, playlists, albums, library, and listening activity.

Those native tools are:

  • spotify_playback
  • spotify_devices
  • spotify_queue
  • spotify_search
  • spotify_playlists
  • spotify_albums
  • spotify_saved_tracks
  • spotify_saved_albums
  • spotify_activity

Together they cover the following action surface:

  • playback control and playback inspection
  • device listing and playback transfer
  • queue inspection and queue add
  • search
  • playlist list/get/create/update/add/remove
  • album get and album track listing
  • saved track list/save/remove
  • saved album list/save/remove
  • recently played and now playing

This approach keeps the integration aligned with Hermes architecture:

  • PKCE-only auth flow
  • no client_secret plaintext config pattern
  • reuse of Hermes auth state storage and credential refresh lifecycle
  • native tool registration and toolset wiring
  • CLI auth commands for login/status/logout

It also includes follow-up UX hardening for Spotify-specific API behavior:

  • friendlier handling for Spotify 401/403/404/429
  • clearer guidance for Premium-gated playback endpoints
  • explanatory handling for 204 No Content on now_playing and playback state

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • Added Spotify PKCE auth support to Hermes auth lifecycle in hermes_cli/auth.py
    • stores provider state under providers.spotify in ~/.hermes/auth.json
    • supports token refresh without changing Hermes' active inference provider
    • reads Spotify config from Hermes env/config path instead of inventing new storage
  • Added CLI auth integration in hermes_cli/auth_commands.py and hermes_cli/main.py
    • hermes auth spotify
    • hermes auth status spotify
    • hermes auth logout spotify
    • logout --provider spotify
  • Added a thin Spotify API client in tools/providers/spotify_client.py
    • centralizes Spotify Web API calls
    • handles auth refresh/retry on 401
    • normalizes Spotify IDs / URLs / URIs
    • adds friendlier error messages for Spotify-specific API responses
    • uses generic /me/library endpoints for saved library operations
  • Added native Spotify tool registration and handlers in tools/spotify_tool.py
  • Added Spotify toolset registration in toolsets.py
  • Added auth/client regression tests:
    • tests/hermes_cli/test_spotify_auth.py
    • tests/tools/test_spotify_client.py

How to Test

  1. Set Spotify app config in Hermes env:
    HERMES_SPOTIFY_CLIENT_ID=...
    HERMES_SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888/callback
    

The redirect URI must be allow-listed in the Spotify developer app.

  1. Authenticate with Spotify:

    hermes auth spotify
    hermes auth status spotify

  2. Verify native tool behavior manually or through Hermes tool dispatch:

    • list devices
    • inspect now_playing / playback state
    • pause/resume playback
    • search tracks
    • add a track to queue
    • list playlists
    • create a temporary playlist, add/remove a track, then clean it up
    • list saved tracks / saved albums
    • save/remove/restore a saved track and saved album
  3. Run automated tests:

    pytest -q tests/tools/test_spotify_client.py tests/hermes_cli/test_spotify_auth.py

Tests Run

Automated:

  • pytest -q tests/tools/test_spotify_client.py tests/hermes_cli/test_spotify_auth.py
  • Result: 13 passed

Unit / regression coverage added for:

  • Spotify auth state persistence
  • refresh flow without clobbering active provider
  • 401 refresh-retry behavior in the client
  • Spotify URL/URI normalization
  • generic /me/library/contains usage
  • generic /me/library remove behavior for saved tracks/albums
  • friendly formatting of Spotify 403/404/429
  • explanatory 204 behavior for empty now_playing
  • explanatory native tool output for spotify_activity now_playing

Manual / live verification against a real Spotify account:

  • PKCE login completed successfully
  • auth state persisted to ~/.hermes/auth.json
  • hermes auth status spotify returned valid logged-in state
  • native device listing succeeded
  • live playback command reached the active Spotify app
  • pause/resume succeeded
  • queue add succeeded
  • playlist listing succeeded
  • album fetch and album track listing succeeded
  • saved tracks listing succeeded
  • saved albums listing succeeded
  • recently played succeeded
  • now_playing native dispatch succeeded
  • native tool dispatch for playlist create/add/remove succeeded
  • temporary playlist cleanup succeeded
  • saved album and saved track write-paths were verified end-to-end:
    • contains -> remove -> contains(false) -> save -> contains(true)

Notable validation after follow-up fix:

  • legacy Spotify library contains endpoints returned 403
  • generic library endpoints (/me/library, /me/library/contains) succeeded
  • the implementation was updated accordingly and re-tested live

Checklist

Code

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide (https://github.com/NousResearch/hermes-agent/blob/main/CONTRIBUTING.md#cross-platform-compatibility) — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/tools Tool registry, model_tools, toolsets comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools labels Apr 24, 2026
teknium1 added a commit that referenced this pull request Apr 24, 2026
Follow-up on top of #15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #15121#15121

Your commit was cherry-picked onto current main with your authorship preserved via rebase-merge. The only follow-up change was gating the Spotify toolset off-by-default: tools were moved out of _HERMES_CORE_TOOLS into the opt-in spotify toolset (same pattern as Home Assistant and RL training), so users who don't use Spotify don't ship 9 extra tool schemas on every API call. Users enable it via hermes tools and then run hermes auth spotify.

Thanks for the thorough PKCE-first design and the live verification — cleanest Spotify integration we've seen.

nekorytaylor666 pushed a commit to nekorytaylor666/hermes-agent that referenced this pull request Apr 24, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
justrhoto pushed a commit to justrhoto/hermes-agent that referenced this pull request Apr 24, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
aj-nt pushed a commit to aj-nt/hermes-agent that referenced this pull request May 1, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
Follow-up on top of NousResearch#15096 cherry-pick:
- Remove spotify_* from _HERMES_CORE_TOOLS (keep only in the 'spotify'
  toolset, so the 9 Spotify tool schemas are not shipped to every user).
- Add 'spotify' to CONFIGURABLE_TOOLSETS + _DEFAULT_OFF_TOOLSETS so new
  installs get it opt-in via 'hermes tools', matching homeassistant/rl.
- Wire TOOL_CATEGORIES entry pointing at 'hermes auth spotify' for the
  actual PKCE login (optional HERMES_SPOTIFY_CLIENT_ID /
  HERMES_SPOTIFY_REDIRECT_URI env vars).
- scripts/release.py: map contributor email to GitHub login.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants