axiom-now-playing-musickit
MusicKit Now Playing integration patterns. Use when playing Apple Music content with ApplicationMusicPlayer and understanding automatic vs manual Now Playing info updates.
Best use case
axiom-now-playing-musickit is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
MusicKit Now Playing integration patterns. Use when playing Apple Music content with ApplicationMusicPlayer and understanding automatic vs manual Now Playing info updates.
Teams using axiom-now-playing-musickit should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/axiom-now-playing-musickit/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How axiom-now-playing-musickit Compares
| Feature / Agent | axiom-now-playing-musickit | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
MusicKit Now Playing integration patterns. Use when playing Apple Music content with ApplicationMusicPlayer and understanding automatic vs manual Now Playing info updates.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# MusicKit Integration (Apple Music)
**Time cost**: 5-10 minutes
## Key Insight
**MusicKit's ApplicationMusicPlayer automatically publishes to MPNowPlayingInfoCenter.** You don't need to manually update Now Playing info when playing Apple Music content.
## What's Automatic
When using `ApplicationMusicPlayer`:
- Track title, artist, album
- Artwork (Apple's album art)
- Duration and elapsed time
- Playback rate (playing/paused state)
The system handles all MPNowPlayingInfoCenter updates for you.
## What's NOT Automatic
- Custom metadata (chapter markers, custom artist notes)
- Remote command customization beyond standard controls
- Mixing MusicKit content with your own content
---
## Subscription and Authorization
### Check Music Authorization
```swift
import MusicKit
func requestMusicAccess() async -> Bool {
let status = await MusicAuthorization.request()
return status == .authorized
}
// Check current status without prompting
let currentStatus = MusicAuthorization.currentStatus
// .authorized, .denied, .notDetermined, .restricted
```
### Check Apple Music Subscription
```swift
func checkSubscription() async -> Bool {
do {
let subscription = try await MusicSubscription.current
return subscription.canPlayCatalogContent
} catch {
return false
}
}
// Observe subscription changes
func observeSubscription() {
Task {
for await subscription in MusicSubscription.subscriptionUpdates {
if subscription.canPlayCatalogContent {
// Full Apple Music access
} else if subscription.canBecomeSubscriber {
// Show subscription offer
showSubscriptionOffer()
}
}
}
}
```
### Subscription Offer Sheet
```swift
import MusicKit
import StoreKit
// Present Apple Music subscription offer
MusicSubscriptionOffer.Options(
messageIdentifier: .playMusic,
itemID: song.id
)
// In SwiftUI
.musicSubscriptionOffer(isPresented: $showOffer, options: offerOptions)
```
### Graceful Fallback Without Subscription
```swift
@MainActor
class MusicPlayer: ObservableObject {
@Published var canPlay = false
func handlePlayRequest(song: Song) async {
let authorized = await requestMusicAccess()
guard authorized else {
showAuthorizationDeniedAlert()
return
}
do {
let subscription = try await MusicSubscription.current
if subscription.canPlayCatalogContent {
// Full playback
try await play(song: song)
} else {
// Preview only (30-second clips)
if let previewURL = song.previewAssets?.first?.url {
playPreview(url: previewURL)
}
}
} catch {
handleError(error)
}
}
}
```
---
## Playback
### Basic Playback
```swift
import MusicKit
@MainActor
class MusicKitPlayer {
private let player = ApplicationMusicPlayer.shared
func play(song: Song) async throws {
// ✅ Just play - MPNowPlayingInfoCenter updates automatically
player.queue = [song]
try await player.play()
// ❌ DO NOT manually set nowPlayingInfo here
// MPNowPlayingInfoCenter.default().nowPlayingInfo = [...] // WRONG!
}
func pause() {
player.pause()
}
func stop() {
player.stop()
}
}
```
### Observing Playback State
```swift
@MainActor
class PlayerViewModel: ObservableObject {
private let player = ApplicationMusicPlayer.shared
@Published var isPlaying = false
@Published var currentEntry: ApplicationMusicPlayer.Queue.Entry?
@Published var playbackTime: TimeInterval = 0
func observeState() {
// Observe playback status
Task {
for await state in player.state.objectWillChange.values {
isPlaying = player.state.playbackStatus == .playing
}
}
// Observe current entry (track changes)
Task {
for await queue in player.queue.objectWillChange.values {
currentEntry = player.queue.currentEntry
}
}
}
}
```
---
## Queue Management
### Setting the Queue
```swift
let player = ApplicationMusicPlayer.shared
// Single song
player.queue = [song]
// Album
player.queue = ApplicationMusicPlayer.Queue(album: album)
// Playlist
player.queue = ApplicationMusicPlayer.Queue(playlist: playlist)
// Multiple items
player.queue = ApplicationMusicPlayer.Queue(for: [song1, song2, song3])
// Start at specific item
player.queue = ApplicationMusicPlayer.Queue(for: songs, startingAt: songs[2])
```
### Queue Operations
```swift
// Skip to next
try await player.skipToNextEntry()
// Skip to previous
try await player.skipToPreviousEntry()
// Restart current track
player.restartCurrentEntry()
// Append to queue
try await player.queue.insert(song, position: .afterCurrentEntry)
try await player.queue.insert(song, position: .tail) // End of queue
// Shuffle and repeat
player.state.shuffleMode = .songs // .off, .songs
player.state.repeatMode = .all // .none, .one, .all
```
### Observing Queue Changes
```swift
// Current track info
if let entry = player.queue.currentEntry {
let title = entry.title
let subtitle = entry.subtitle // Artist name
let artwork = entry.artwork // Artwork for display
// Get full Song object if needed
if case .song(let song) = entry.item {
let albumTitle = song.albumTitle
}
}
```
---
## Hybrid Apps (Own Content + Apple Music)
If your app plays both Apple Music and your own content:
```swift
import MusicKit
@MainActor
class HybridPlayer {
private let musicKitPlayer = ApplicationMusicPlayer.shared
private var avPlayer: AVPlayer?
private var currentSource: ContentSource = .none
enum ContentSource {
case none
case appleMusic // MusicKit handles Now Playing
case ownContent // We handle Now Playing
}
func playAppleMusicSong(_ song: Song) async throws {
// Switch to MusicKit
avPlayer?.pause()
currentSource = .appleMusic
musicKitPlayer.queue = [song]
try await musicKitPlayer.play()
// ✅ MusicKit handles Now Playing automatically
}
func playOwnContent(_ url: URL) {
// Switch to AVPlayer
musicKitPlayer.pause()
currentSource = .ownContent
avPlayer = AVPlayer(url: url)
avPlayer?.play()
// ✅ Manually update Now Playing (see axiom-now-playing)
updateNowPlayingForOwnContent()
}
private func updateNowPlayingForOwnContent() {
var nowPlayingInfo = [String: Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = "My Track"
// ... rest of manual setup
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
}
```
---
## Common Mistake
```swift
// ❌ WRONG - Overwrites MusicKit's automatic Now Playing data
func playAppleMusicSong(_ song: Song) async throws {
try await ApplicationMusicPlayer.shared.play()
// ❌ This clears MusicKit's Now Playing info!
var nowPlayingInfo = [String: Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = song.title
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
// ✅ CORRECT - Let MusicKit handle it
func playAppleMusicSong(_ song: Song) async throws {
try await ApplicationMusicPlayer.shared.play()
// That's it! MusicKit publishes Now Playing automatically.
}
```
## When to Use Manual Updates with MusicKit
Only override MPNowPlayingInfoCenter if:
- You're mixing in additional metadata (e.g., podcast chapter markers)
- You're displaying custom content alongside Apple Music
- You have a specific reason to replace MusicKit's automatic behavior
**Default**: Let MusicKit manage Now Playing automatically.
## Resources
**Docs**: /musickit, /musickit/applicationmusicplayer, /musickit/musicsubscription
**Skills**: axiom-now-playing, axiom-now-playing-carplayRelated Skills
axiom-audit
Audit Axiom logs to identify and prioritize errors and warnings, research probable causes, and flag log smells. Use when user asks to check Axiom logs, analyze production errors, investigate log issues, or audit logging patterns.
Axiom — Serverless Log Analytics
## Overview
axiom-xctrace-ref
Use when automating Instruments profiling, running headless performance analysis, or integrating profiling into CI/CD - comprehensive xctrace CLI reference with record/export patterns
axiom-xctest-automation
Use when writing, running, or debugging XCUITests. Covers element queries, waiting strategies, accessibility identifiers, test plans, and CI/CD test execution patterns.
axiom-xcode-mcp
Use when connecting to Xcode via MCP, using xcrun mcpbridge, or working with ANY Xcode MCP tool (XcodeRead, BuildProject, RunTests, RenderPreview). Covers setup, tool reference, workflow patterns, troubleshooting.
axiom-xcode-mcp-tools
Xcode MCP workflow patterns — BuildFix loop, TestFix loop, preview verification, window targeting, tool gotchas
axiom-xcode-mcp-setup
Xcode MCP setup — enable mcpbridge, per-client config, permission handling, multi-Xcode targeting, troubleshooting
axiom-xcode-mcp-ref
Reference — all 20 Xcode MCP tools with parameters, return schemas, and examples
axiom-xcode-debugging
Use when encountering BUILD FAILED, test crashes, simulator hangs, stale builds, zombie xcodebuild processes, "Unable to boot simulator", "No such module" after SPM changes, or mysterious test failures despite no code changes - systematic environment-first diagnostics for iOS/macOS projects
axiom-xclog-ref
Use when capturing iOS simulator console output, diagnosing runtime crashes, viewing print/os_log output, or needing structured app logs for analysis. Reference for xclog CLI covering launch, attach, list modes with JSON output.
axiom-vision
subject segmentation, VNGenerateForegroundInstanceMaskRequest, isolate object from hand, VisionKit subject lifting, image foreground detection, instance masks, class-agnostic segmentation, VNRecognizeTextRequest, OCR, VNDetectBarcodesRequest, DataScannerViewController, document scanning, RecognizeDocumentsRequest
axiom-vision-ref
Use when needing Vision framework API details for hand/body pose, segmentation, text recognition, barcode detection, document scanning, or Visual Intelligence integration. Covers VNRequest types, coordinate conversion, DataScannerViewController, RecognizeDocumentsRequest, SemanticContentDescriptor, IntentValueQuery.