diff --git a/.planning/phases/01-backing-track-playback-monitoring/01-01-PLAN.md b/.planning/phases/01-backing-track-playback-monitoring/01-01-PLAN.md
new file mode 100644
index 000000000..755c95860
--- /dev/null
+++ b/.planning/phases/01-backing-track-playback-monitoring/01-01-PLAN.md
@@ -0,0 +1,215 @@
+---
+phase: 01-backing-track-playback-monitoring
+type: execute
+---
+
+
+Implement real-time playback monitoring for the backing track player by adding 500ms polling of the native client and displaying current position and duration in M:SS format.
+
+Purpose: Complete the player's time display functionality, matching the legacy web implementation's polling pattern while using modern React hooks. This establishes the monitoring foundation that Phase 2 (seek controls) will build upon.
+
+Output: Backing track player with live-updating time displays showing current position and total duration while track plays.
+
+
+
+@./.claude/get-shit-done/workflows/execute-phase.md
+@./.claude/get-shit-down/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+@.planning/phases/01-backing-track-playback-monitoring/1-CONTEXT.md
+@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
+
+**Codebase conventions:**
+- React functional components with hooks (React 16.13.1)
+- camelCase for functions and variables
+- Single quotes for strings (Prettier enforced)
+- 2-space indentation
+
+**Legacy implementation reference:**
+- web/app/assets/javascripts/playbackControls.js: 500ms polling via setTimeout (lines 301-337)
+- web/app/assets/javascripts/utils.js: prettyPrintSeconds() time formatting (lines 885-906)
+- jamClient methods: SessionCurrrentPlayPosMs(), SessionGetTracksPlayDurationMs(), isSessionTrackPlaying()
+
+**Current state:**
+- JKSessionBackingTrackPlayer.js has currentTime and duration state hardcoded to "0:00" (lines 20-21)
+- Play/pause/stop controls work via jamClient (lines 34-58)
+- UI structure already in place with time displays (lines 207, 217 for popup; lines 302, 312 for modal)
+
+**Vision from CONTEXT.md:**
+- Functional parity with legacy web (500ms polling, accurate time display)
+- UI layout: Current time (M:SS) on left of slider, duration (M:SS) on right
+- No padding on single-digit minutes (1:02 not 01:02)
+
+
+
+
+
+ Task 1: Add formatTime utility function
+ jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
+ Add a formatTime utility function to convert milliseconds to M:SS format (matching legacy web prettyPrintSeconds behavior). Place it inside the component before the useEffect hooks.
+
+Implementation:
+- Accept milliseconds as parameter
+- Convert to seconds (Math.floor(ms / 1000))
+- Calculate minutes: Math.floor(seconds / 60)
+- Calculate remaining seconds: seconds % 60
+- Pad seconds with "0" if less than 10 (e.g., "1:05" not "1:5")
+- NO padding on minutes (single digit is fine: "1:02" not "01:02")
+- Return formatted string: `${minutes}:${seconds.toString().padStart(2, '0')}`
+
+Example outputs:
+- formatTime(62000) → "1:02"
+- formatTime(313000) → "5:13"
+- formatTime(3605000) → "60:05"
+
+Do NOT implement hours formatting (tracks are < 60 minutes).
+ Add console.log tests:
+- formatTime(62000) should output "1:02"
+- formatTime(313000) should output "5:13"
+- formatTime(0) should output "0:00"
+ formatTime function exists, converts milliseconds to M:SS format with proper padding (seconds only)
+
+
+
+ Task 2: Add playback monitoring with 500ms polling
+ jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
+ Add useEffect hook for playback monitoring with 500ms polling interval matching legacy web implementation (web/app/assets/javascripts/playbackControls.js lines 301-337).
+
+Implementation:
+- Add useEffect that runs when isPlaying changes
+- When isPlaying is true, start polling:
+ - Use setInterval (not setTimeout recursion) with 500ms interval
+ - In interval callback:
+ 1. Check if jamClient exists (guard against undefined)
+ 2. Call jamClient.SessionCurrrentPlayPosMs() → current position in ms
+ 3. Call jamClient.SessionGetTracksPlayDurationMs() → total duration in ms
+ 4. Call jamClient.isSessionTrackPlaying() → boolean for playing state
+ 5. Update setCurrentTime(formatTime(positionMs))
+ 6. Update setDuration(formatTime(durationMs))
+ 7. Sync setIsPlaying(isPlaying) if state changed
+- When isPlaying is false, clear the interval
+- Return cleanup function that clears interval
+
+Error handling:
+- Wrap jamClient calls in try/catch
+- On error, log to console but don't crash
+- Continue polling even if one poll fails
+
+Dependencies: [isPlaying, jamClient, backingTrack]
+
+IMPORTANT: Use setInterval (not setTimeout recursion) for consistent 500ms timing. Store intervalId in a variable to clear on cleanup.
+ Check console logs show:
+1. When play clicked: Polling starts, position/duration update every 500ms
+2. When pause clicked: Polling stops, interval cleared
+3. When stop clicked: Polling stops, position resets to 0:00
+4. No errors logged during playback
+ Playback monitoring polls jamClient every 500ms when playing, updates currentTime and duration state with formatted values, cleans up interval on pause/stop
+
+
+
+ Task 3: Initialize duration on track load
+ jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
+ Modify the existing useEffect (lines 25-32) that runs when track opens to fetch and set initial duration immediately, not waiting for playback to start.
+
+Current code:
+```javascript
+useEffect(() => {
+ if (isOpen && backingTrack) {
+ setIsPlaying(false);
+ setCurrentTime('0:00');
+ setDuration('0:00');
+ }
+}, [isOpen, backingTrack]);
+```
+
+Change to:
+```javascript
+useEffect(() => {
+ if (isOpen && backingTrack && jamClient) {
+ setIsPlaying(false);
+ setCurrentTime('0:00');
+
+ // Fetch and set duration immediately when track loads
+ try {
+ const durationMs = jamClient.SessionGetTracksPlayDurationMs();
+ setDuration(formatTime(durationMs));
+ } catch (error) {
+ console.error('Error fetching track duration:', error);
+ setDuration('0:00');
+ }
+ }
+}, [isOpen, backingTrack, jamClient]);
+```
+
+This ensures the duration appears immediately when the player opens, matching the UI in the reference screenshot where "5:13" is visible before playback starts.
+ Open backing track player without playing:
+- Duration displays actual track length (e.g., "5:13") immediately
+- Current time shows "0:00"
+- No errors in console
+ Duration fetched and displayed when track loads (before play starts), matching legacy web behavior
+
+
+
+
+
+Before declaring phase complete:
+- [ ] Open backing track player, verify duration shows immediately (e.g., "5:13")
+- [ ] Click play, verify current time updates every ~500ms (1:00 → 1:01 → 1:02)
+- [ ] Verify time format matches reference: M:SS (no leading zero on minutes)
+- [ ] Click pause, verify polling stops (time freezes)
+- [ ] Click play again, verify polling resumes from paused position
+- [ ] Click stop, verify time resets to "0:00"
+- [ ] Check browser console for errors (should be none)
+- [ ] Verify both modal and popup versions work identically
+
+
+
+
+- formatTime utility converts milliseconds to M:SS format correctly
+- Playback monitoring polls jamClient every 500ms when playing
+- Current time display updates smoothly during playback
+- Duration displays immediately when track loads
+- Polling stops cleanly when paused/stopped
+- No console errors during playback
+- Functional parity with legacy web monitoring behavior
+
+
+