# Send SpotiClaw to your agent
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
## Fast path
- Download the package from Yavira.
- Extract it into a folder your agent can access.
- Paste one of the prompts below and point your agent at the extracted folder.
## Suggested prompts
### New install

```text
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete.
```
### Upgrade existing

```text
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run.
```
## Machine-readable fields
```json
{
  "schemaVersion": "1.0",
  "item": {
    "slug": "spoticlaw",
    "name": "SpotiClaw",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/ledzgio/spoticlaw",
    "canonicalUrl": "https://clawhub.ai/ledzgio/spoticlaw",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadUrl": "/downloads/spoticlaw",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=spoticlaw",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "packageFormat": "ZIP package",
    "primaryDoc": "SKILL.md",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "scripts/__init__.py",
      "scripts/auth.py",
      "scripts/requirements.txt",
      "scripts/spoticlaw.py"
    ],
    "downloadMode": "redirect",
    "sourceHealth": {
      "source": "tencent",
      "slug": "spoticlaw",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-09T09:27:07.535Z",
      "expiresAt": "2026-05-16T09:27:07.535Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=spoticlaw",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=spoticlaw",
        "contentDisposition": "attachment; filename=\"spoticlaw-1.0.7.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "spoticlaw"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/spoticlaw"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    }
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/spoticlaw",
    "downloadUrl": "https://openagent3.xyz/downloads/spoticlaw",
    "agentUrl": "https://openagent3.xyz/skills/spoticlaw/agent",
    "manifestUrl": "https://openagent3.xyz/skills/spoticlaw/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/spoticlaw/agent.md"
  }
}
```
## Documentation

### Spoticlaw - Spotify Web API Client

A lightweight Spotify Web API client using direct HTTP requests. No Spotipy dependency.

### Quick Start

# Install dependencies
pip install requests python-dotenv

# Add to path
import sys
sys.path.insert(0, "skills/spoticlaw/scripts")

from spoticlaw import player, search, playlists, library

# Search for music
results = search().query("coldplay", types=["track"], limit=10)

# Play a track
player().play(uris=["spotify:track:..."])

# Manage playlists
playlists().create("My Playlist")
playlists().add_items("playlist_id", ["spotify:track:..."])

# Save to library
library().save(["spotify:track:..."])

Or run from the scripts directory:

cd skills/spoticlaw/scripts
python -c "from spoticlaw import player; player().play(...)"

### Required Configuration

Required env vars in agent runtime:

SPOTIFY_CLIENT_ID
SPOTIFY_CLIENT_SECRET
SPOTIFY_REDIRECT_URI (recommended: http://127.0.0.1:8888/callback)

Required file:

.spotify_cache (OAuth token cache)

### Authentication

Security Note: Tokens never pass through the AI model. Authentication is done locally, and the token file is copied manually to the agent.

### Setup

Create a Spotify app at https://developer.spotify.com/dashboard
Get CLIENT_ID and CLIENT_SECRET
Add http://127.0.0.1:8888/callback as Redirect URI
Create .env file in your LOCAL machine:

SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888/callback

Run authentication on your LOCAL machine:

cd skills/spoticlaw/scripts
pip install -r requirements.txt
python auth.py

Open the displayed URL in your browser, authorize


Copy the token file to your agent:

# Linux/Mac - copy to agent's skill folder
cp .spotify_cache /path/to/agent/skills/spoticlaw/.spotify_cache

# Or if agent is remote, copy via scp, USB, etc.
scp .spotify_cache user@agent:/path/to/skills/spoticlaw/.spotify_cache

That's it! No token ever touches the AI. The agent just reads the file.

### Token Auto-Refresh

The library automatically handles token refresh only if the agent has the same app credentials in .env:

Access token expires after ~1 hour
On first API call after expiry, it uses refresh_token + client credentials to request a new access token
Requires SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET in the agent environment
If .spotify_cache exists but .env is missing/mismatched, refresh fails (invalid_client)
If you get an error, run python auth.py locally again and copy updated .spotify_cache

For more on Spotify's OAuth flow, see: https://developer.spotify.com/documentation/web-api/tutorials/code-flow

### Required Scopes

The auth.py script requests these scopes:

user-read-playback-state - Read playback state
user-modify-playback-state - Control playback
playlist-read-private - Read private playlists
playlist-modify-public - Modify public playlists
playlist-modify-private - Modify private playlists
user-library-read - Read user library
user-library-modify - Modify user library
user-read-recently-played - Recently played tracks
user-top-read - Top tracks/artists
user-follow-read - Followed artists

### Primitives

Important: Add the module path and install deps first:

pip install requests python-dotenv  # Install dependencies

# For agent execution, add to path:
import sys
sys.path.insert(0, "skills/spoticlaw/scripts")

### User

from spoticlaw import user

user().me()  # Get current user profile

Returns: {id, display_name, email, country, ...}

### Search

from spoticlaw import search

# Search for tracks
search().query("song name", types=["track"], limit=10)

# Search for artists
search().query("artist name", types=["artist"], limit=10)

# Search multiple types
search().query("coldplay", types=["track", "artist", "album"], limit=10)

Parameters:

q: Search query string
types: List of types: track, artist, album, playlist, show, episode, audiobook
limit: Max 10 results (Spotify limit)
offset: Pagination offset

### Tracks

from spoticlaw import tracks

tracks().get("track_id")  # Get single track
tracks().get_multiple(["id1", "id2"])  # Get multiple tracks

Returns track metadata: {name, artists, album, duration_ms, uri, ...}

### Artists

from spoticlaw import artists

artists().get("artist_id")  # Get artist details
artists().get_albums("artist_id", limit=10)  # Get artist albums

Album filters (include_groups):

album, single, compilation, appears_on

### Albums

from spoticlaw import albums

albums().get("album_id")  # Get album details
albums().get_tracks("album_id")  # Get album tracks

### Shows (Podcasts)

from spoticlaw import shows

shows().get("show_id")  # Get show details
shows().get_episodes("show_id", limit=10)  # Get show episodes

### Episodes

from spoticlaw import episodes

episodes().get("episode_id")  # Get episode details

### Playlists

from spoticlaw import playlists, user_playlists

# Get user's playlists
user_playlists().get(limit=50)

# Get playlist details
playlists().get("playlist_id")

# Get playlist tracks
# Note: Each item has 'item' key (not 'track'), e.g. item['item']['name']
# Also can contain episodes (podcasts), not just tracks
playlists().get_items("playlist_id", limit=50)

# Create playlist
playlists().create(name="My Playlist", description="...", public=False)

# Update playlist
playlists().update("playlist_id", name="New Name")

# Add tracks
playlists().add_items("playlist_id", ["spotify:track:...", "spotify:track:..."])

# Remove tracks
playlists().remove_items("playlist_id", ["spotify:track:..."])

# Delete playlist (unfollow)
playlists().delete("playlist_id")

### Library

from spoticlaw import library

library().save(["spotify:track:..."])  # Save to library
library().remove(["spotify:track:..."])  # Remove from library
library().check(["spotify:track:..."])  # Check if saved, returns [True, False]

### Player

from spoticlaw import player

# Get playback state
player().get_playback_state()  # Returns {} if nothing playing
player().get_currently_playing()

# Get devices
player().get_devices()  # Returns list of devices with IDs

# Transfer playback to device
player().transfer("device_id", play=True)

# Playback control
player().play(uris=["spotify:track:..."])  # Start playing
player().play(context_uri="spotify:album:...")  # Play album/playlist
player().pause()
player().next()
player().previous()
player().seek(60000)  # Seek to 1:00 (milliseconds)
player().set_volume(80)  # Set volume 0-100

# Queue
player().add_to_queue("spotify:track:...")
player().get_queue()

# Modes
player().set_shuffle(True)
player().set_repeat("off")  # off, track, context

# Recently played
player().get_recently_played(limit=50)

### Personalisation

from spoticlaw import personalisation

personalisation().get_top("tracks", time_range="medium_term", limit=20)
personalisation().get_top("artists", time_range="long_term", limit=20)

# time_range: short_term (4 weeks), medium_term (6 months), long_term (years)

### Follow

from spoticlaw import follow

follow().get_followed(limit=50)  # Get followed artists

### Composite Workflows

The primitives can be mixed and matched to create powerful automations. Here are practical examples:

### Workflow 1: Play a Specific Song

from spoticlaw import search, player

# 1. Search for the song
results = search().query("stairway to heaven", types=["track"], limit=5)
song = results["tracks"]["items"][0]
song_uri = song["uri"]
print(f"Playing: {song['name']} by {song['artists'][0]['name']}")

# 2. Play it
player().play(uris=[song_uri])

### Workflow 2: Create Playlist from Search Results

from spoticlaw import search, playlists

# 1. Search for songs
results = search().query("led zeppelin", types=["track"], limit=10)
track_uris = [t["uri"] for t in results["tracks"]["items"][:5]]

# 2. Create playlist
pl = playlists().create("Led Zeppelin Mix", public=False)
playlist_id = pl["id"]

# 3. Add tracks
playlists().add_items(playlist_id, track_uris)
print(f"Created playlist: {pl['name']}")

### Workflow 3: Save Album to Library

from spoticlaw import artists, albums, library

# 1. Find artist
artist = search().query("the weeknd", types=["artist"], limit=1)["artists"]["items"][0]

# 2. Get albums
albums_list = artists().get_albums(artist["id"], include_groups="album", limit=5)

# 3. Save first album
album = albums_list["items"][0]
library().save([album["uri"]])
print(f"Saved album: {album['name']}")

### Workflow 4: Play Podcast Episode

from spoticlaw import search, shows, player

# 1. Find podcast
podcast = search().query("joe rogan", types=["show"], limit=1)["shows"]["items"][0]
show_id = podcast["id"]

# 2. Get latest episode
episodes = shows().get_episodes(show_id, limit=1)
episode = episodes["items"][0]
episode_uri = episode["uri"]

# 3. Get device and play
devices = player().get_devices()
if devices.get("devices"):
    device_id = devices["devices"][0]["id"]
    player().transfer(device_id, play=True)
    player().play(uris=[episode_uri])
    print(f"Playing: {episode['name']}")

### Workflow 5: Transfer Playback and Play

from spoticlaw import player, search

# 1. Get available devices
devices = player().get_devices()
print("Available devices:", [d["name"] for d in devices.get("devices", [])])

# 2. Transfer to phone
if devices.get("devices"):
    device_id = devices["devices"][0]["id"]
    player().transfer(device_id, play=True)
    
    # 3. Search and play
    results = search().query("dream on", types=["track"], limit=1)
    track_uri = results["tracks"]["items"][0]["uri"]
    player().play(uris=[track_uri])

### Workflow 6: Get User's Top Artists and Follow One

from spoticlaw import personalisation, search, library

# 1. Get top artists
top = personalisation().get_top("artists", limit=10)
print("Your top artists:")
for i, a in enumerate(top["items"], 1):
    print(f"  {i}. {a['name']}")

# 2. Search for a new artist
new_artist = search().query("tame impala", types=["artist"], limit=1)["artists"]["items"][0]
print(f"\\nFound: {new_artist['name']}")

# Note: Follow functionality requires additional scope (not in current scope list)
# Use Spotify app to follow manually

### Workflow 7: Build Queue from Album

from spoticlaw import albums, player

# 1. Get album tracks
album_id = "4aawyAB9vmqN3uQ7FjRGTy"  # Example album
tracks = albums().get_tracks(album_id)

# 2. Add all tracks to queue
for track in tracks["items"][:5]:  # First 5 tracks
    player().add_to_queue(track["uri"])

print("Added 5 tracks to queue")

### Workflow 8: Check Library for Multiple Tracks

from spoticlaw import library, search

# 1. Search for tracks
results = search().query("classic rock", types=["track"], limit=20)
track_uris = [t["uri"] for t in results["tracks"]["items"]]

# 2. Check which are in library
saved = library().check(track_uris)

# 3. Show results
for i, (track, is_saved) in enumerate(zip(results["tracks"]["items"], saved)):
    status = "✓ saved" if is_saved else "○ not saved"
    print(f"{i+1}. {track['name']} - {status}")

### Workflow 9: Get Recently Played and Save One

from spoticlaw import player, library

# 1. Get recently played
recent = player().get_recently_played(limit=10)

print("Recently played:")
for i, item in enumerate(recent["items"], 1):
    track = item["track"]
    print(f"  {i}. {track['name']} - {track['artists'][0]['name']}")

# 2. Save the first one
if recent["items"]:
    track_uri = recent["items"][0]["track"]["uri"]
    library().save([track_uri])
    print(f"\\nSaved: {recent['items'][0]['track']['name']}")

### Workflow 10: Play from Playlist

from spoticlaw import playlists, player

# 1. Get user's playlists
my_playlists = user_playlists().get(limit=10)

print("Your playlists:")
for p in my_playlists["items"]:
    print(f"  - {p['name']} ({p['tracks']['total']} tracks)")

# 2. Pick first playlist and play
if my_playlists["items"]:
    playlist_id = my_playlists["items"][0]["id"]
    # Get device first
    devices = player().get_devices()
    if devices.get("devices"):
        player().transfer(devices["devices"][0]["id"], play=True)
        
        # Play playlist
        player().play(context_uri=f"spotify:playlist:{playlist_id}")
        print(f"Playing: {my_playlists['items'][0]['name']}")

### Error Handling

from spoticlaw import player, SpotifyException

try:
    player().play(uris=["spotify:track:..."])
except SpotifyException as e:
    if "NO_ACTIVE_DEVICE" in str(e):
        print("No device found. Open Spotify and try again.")
    elif "Invalid token" in str(e):
        print("Token expired. Re-authenticate: python auth.py")
    else:
        print(f"Error: {e}")

### Common Issues

ErrorSolutionNo token. Re-authenticate.Run python auth.pyThe access token expiredShould auto-refresh. If not, run python auth.pyInsufficient client scopeRe-auth with more scopesNO_ACTIVE_DEVICEOpen Spotify app, then retryInvalid limitUse max 10 for search, 50 for playlistsResource not foundInvalid ID or item unavailable

### API Limits

Search: max 10 results
Playlist items: max 50
Pagination: Use offset parameter
Player: Requires active Spotify session

### Files

scripts/spoticlaw.py - Main API client
scripts/auth.py - Authentication helper
scripts/requirements.txt - Dependencies

### More Info

For setup, troubleshooting, and contributions:
https://github.com/your-org/spoticlaw
## Trust
- Source: tencent
- Verification: Indexed source record
- Publisher: ledzgio
- Version: 1.0.7
## Source health
- Status: healthy
- Item download looks usable.
- Yavira can redirect you to the upstream package for this item.
- Health scope: item
- Reason: direct_download_ok
- Checked at: 2026-05-09T09:27:07.535Z
- Expires at: 2026-05-16T09:27:07.535Z
- Recommended action: Download for OpenClaw
## Links
- [Detail page](https://openagent3.xyz/skills/spoticlaw)
- [Send to Agent page](https://openagent3.xyz/skills/spoticlaw/agent)
- [JSON manifest](https://openagent3.xyz/skills/spoticlaw/agent.json)
- [Markdown brief](https://openagent3.xyz/skills/spoticlaw/agent.md)
- [Download page](https://openagent3.xyz/downloads/spoticlaw)