Imported from SheltonTolbert/Apple-Music-Playlist-CLI (
AGENTS.md). Install upstream withnpx skills add SheltonTolbert/Apple-Music-Playlist-CLI. Copyright stays with the author.
Agent workflow notes
This repository is a small macOS CLI for Music.app playlist management. The entrypoint is:
zsh src/am.sh playlist <command> [args]
Use these notes when an agent is asked to create or populate Apple Music playlists, especially large CSV-driven catalog imports.
Permission requirements
Before attempting write operations, verify the host can control Music.app:
osascript -e 'id of application "Music"'
zsh src/am.sh playlist list
For local Music.app playlist operations, macOS Automation permission is required for the terminal or agent host process that runs osascript. If macOS prompts, grant access in System Settings > Privacy & Security > Automation.
For the no-token GUI fallback, Accessibility permission is also required for the terminal or agent host process. Verify it with:
osascript -e 'tell application "System Events" to get UI elements enabled'
If it returns false or reports that the process is not allowed assistive access, grant the host app in System Settings > Privacy & Security > Accessibility. In some Python-based agent sessions, the host app may be Python.app rather than Terminal.app.
The API catalog write path requires these environment variables for real writes:
export APPLE_MUSIC_DEVELOPER_TOKEN="..."
export APPLE_MUSIC_USER_TOKEN="..."
Do not print token values in logs.
Happy path for a large playlist import
-
Start from a clean repo and inspect the CLI help.
git status --short zsh src/am.sh playlist help zsh src/am.sh playlist add-gui help -
Inspect the input CSV or song list. Normalize title and artist fields in a separate import script, apply any requested exclusions, and de-duplicate before mutating Music.app.
-
Create or verify the target playlist.
zsh src/am.sh playlist create "Playlist Name" zsh src/am.sh playlist show "Playlist Name" -
Probe local-library coverage first.
zsh src/am.sh playlist add "Playlist Name" "Known Track Name"playlist addonly duplicates tracks already present in Music.app's Library. If common tracks are missing locally, switch to catalog search/API or the GUI fallback instead of looping local adds. -
Resolve catalog tracks with dry runs.
zsh src/am.sh playlist search "Track Name" "Artist Name" zsh src/am.sh playlist add-catalog "Playlist Name" "Track Name" "Artist Name" --dry-runIf the search returns multiple variants, capture the desired catalog
trackIdand use--track-idfor exact selection. -
Prefer the token-backed API path for bulk writes when Apple Music tokens are available.
zsh src/am.sh playlist add-catalog "Playlist Name" "Track Name" "Artist Name" --track-id 123456789 -
If tokens are not available, use the no-token GUI fallback only after a one-song smoke test succeeds.
zsh src/am.sh playlist add-gui "Playlist Name" "Track Name" "Artist Name" --track-id 123456789 --wait 3 zsh src/am.sh playlist show "Playlist Name" -
Run the bulk import through the reusable importer so the workflow is resumable and logs every row.
python3 scripts/import_playlist.py songs.csv "Playlist Name" \ --mode add-gui \ --exclude-artist U2 \ --exclude-artist Coldplay \ --track-id-map track-ids.json \ --output-dir runs/my-playlist-import \ --wait 3Recommended statuses are produced in
runs/my-playlist-import/status.tsv:added,already_present,skipped_existing,excluded,missing_data,dry_run, anderror. Use--dry-runfirst when validating CSV columns or command generation. -
Verify the final playlist count with Music.app, not only with script output.
zsh src/am.sh playlist show "Playlist Name" -
Before committing, remove generated import scripts, result TSVs, pycache files, and other one-off artifacts. Commit only reusable CLI changes and documentation.
What eventually worked for the 97X-style import
The successful fallback path was:
- Use public iTunes/Apple Music search to identify likely catalog songs.
- For ambiguous or title-variant misses, use concrete iTunes/Apple Music track IDs and call
add-gui ... --track-id <id>. - Open the catalog URL with
open -a Music <url>rather than relying only on Music.app AppleScriptopen location; this was more reliable at actually navigating Music.app to the track page. - Let Music.app add the catalog song to the user's Library through the visible UI.
- After the song appeared in
playlist "Library", duplicate the local Library track into the target user playlist. - Log each row and retry failures by track ID or by cleaner title variants.
Pitfalls discovered
playlist addis local-library only. It cannot add arbitrary Apple Music catalog songs that are not already in Music.app's Library.- A successful catalog search does not guarantee a playlist write. API writes require valid MusicKit developer and user tokens, and the target playlist must be visible as a mutable cloud library playlist.
- Music.app AppleScript
open locationmay leave the app on the previous page or a blank placeholder.open -a Music <catalog-url>worked more reliably for catalog URLs. - The visible add control in Music.app is not always named exactly
Add. Accessibility may expose it asAdd buttonor as a button whose description isDownload button. - System Events can fail with no
window 1for Music.app. Bring back the main Music window with Cmd-0, then retry. - Some catalog entries use canonical titles that differ from radio-list titles, for example subtitles, punctuation, or featured-artist formatting. Use
playlist searchand--track-idrather than forcing an inexact title match. - Do not add covers, live versions, remasters, or karaoke versions as substitutes unless the user explicitly approves them.
- Device/account limits in Music.app can block further catalog-library adds. If Music.app reports a device limit, stop and ask the user to resolve it in Account Settings.
- GUI automation is slow and fragile for 100+ songs. Test one song, then a small batch, before running a full import.
Agent hygiene
-
Keep generated import logs under
runs/; reusable import code belongs inscripts/and should have tests undertests/. -
Do not commit credentials, tokens, MusicKit user tokens, or raw environment dumps.
-
Use
--dry-runand one-song smoke tests before bulk mutation. -
Verify final state with
playlist showand report both source-row counts and actual playlist counts. -
If modifying
src/am.sh, run a syntax check before committing:zsh -n src/am.sh