livepilot 1.27.1 → 1.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +10 -7
  3. package/bin/livepilot.js +156 -37
  4. package/livepilot/.Codex-plugin/plugin.json +1 -1
  5. package/livepilot/.claude-plugin/plugin.json +1 -1
  6. package/livepilot/skills/livepilot-core/SKILL.md +33 -1
  7. package/livepilot/skills/livepilot-core/references/atlas-tool-notes.md +69 -0
  8. package/livepilot/skills/livepilot-core/references/overview.md +18 -11
  9. package/livepilot/skills/livepilot-core/references/perception.md +125 -0
  10. package/livepilot/skills/livepilot-devices/references/device-parameter-units.md +66 -0
  11. package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
  12. package/livepilot/skills/livepilot-mix-engine/SKILL.md +8 -0
  13. package/livepilot/skills/livepilot-release/SKILL.md +1 -1
  14. package/livepilot/skills/livepilot-sample-engine/references/splice-tools-notes.md +56 -0
  15. package/livepilot/skills/livepilot-wonder/SKILL.md +6 -0
  16. package/m4l_device/LivePilot_Analyzer.amxd +0 -0
  17. package/m4l_device/livepilot_bridge.js +48 -11
  18. package/mcp_server/__init__.py +1 -1
  19. package/mcp_server/atlas/__init__.py +181 -40
  20. package/mcp_server/atlas/overlays.py +46 -3
  21. package/mcp_server/atlas/tools.py +226 -86
  22. package/mcp_server/audit/checks.py +50 -22
  23. package/mcp_server/audit/state.py +10 -2
  24. package/mcp_server/audit/tools.py +27 -6
  25. package/mcp_server/composer/develop/apply.py +7 -7
  26. package/mcp_server/composer/fast/apply.py +29 -23
  27. package/mcp_server/composer/fast/brief_builder.py +6 -2
  28. package/mcp_server/composer/framework/atlas_resolver.py +16 -1
  29. package/mcp_server/composer/full/apply.py +40 -34
  30. package/mcp_server/composer/full/engine.py +66 -32
  31. package/mcp_server/composer/tools.py +16 -9
  32. package/mcp_server/connection.py +69 -10
  33. package/mcp_server/creative_constraints/engine.py +10 -2
  34. package/mcp_server/creative_constraints/tools.py +24 -7
  35. package/mcp_server/curves.py +30 -7
  36. package/mcp_server/device_forge/builder.py +40 -11
  37. package/mcp_server/device_forge/models.py +9 -0
  38. package/mcp_server/device_forge/tools.py +30 -11
  39. package/mcp_server/experiment/engine.py +29 -22
  40. package/mcp_server/experiment/tools.py +15 -5
  41. package/mcp_server/m4l_bridge.py +217 -62
  42. package/mcp_server/memory/taste_graph.py +43 -0
  43. package/mcp_server/memory/technique_store.py +26 -3
  44. package/mcp_server/memory/tools.py +62 -4
  45. package/mcp_server/mix_engine/critics.py +187 -30
  46. package/mcp_server/mix_engine/models.py +21 -1
  47. package/mcp_server/mix_engine/state_builder.py +87 -8
  48. package/mcp_server/mix_engine/tools.py +16 -4
  49. package/mcp_server/performance_engine/tools.py +56 -8
  50. package/mcp_server/persistence/base_store.py +11 -0
  51. package/mcp_server/persistence/project_store.py +132 -8
  52. package/mcp_server/persistence/taste_store.py +90 -7
  53. package/mcp_server/preview_studio/engine.py +40 -10
  54. package/mcp_server/preview_studio/models.py +40 -0
  55. package/mcp_server/preview_studio/tools.py +56 -12
  56. package/mcp_server/project_brain/arrangement_graph.py +4 -0
  57. package/mcp_server/project_brain/models.py +2 -0
  58. package/mcp_server/project_brain/role_graph.py +13 -7
  59. package/mcp_server/reference_engine/gap_analyzer.py +58 -3
  60. package/mcp_server/reference_engine/profile_builder.py +47 -4
  61. package/mcp_server/reference_engine/tools.py +6 -0
  62. package/mcp_server/runtime/execution_router.py +57 -1
  63. package/mcp_server/runtime/mcp_dispatch.py +22 -0
  64. package/mcp_server/runtime/remote_commands.py +9 -4
  65. package/mcp_server/runtime/tools.py +0 -1
  66. package/mcp_server/sample_engine/sources.py +0 -2
  67. package/mcp_server/sample_engine/tools.py +19 -38
  68. package/mcp_server/semantic_moves/mix_compilers.py +276 -51
  69. package/mcp_server/semantic_moves/performance_compilers.py +51 -17
  70. package/mcp_server/semantic_moves/resolvers.py +45 -0
  71. package/mcp_server/semantic_moves/sound_design_compilers.py +14 -6
  72. package/mcp_server/semantic_moves/tools.py +80 -2
  73. package/mcp_server/semantic_moves/transition_compilers.py +26 -9
  74. package/mcp_server/server.py +27 -25
  75. package/mcp_server/session_continuity/tracker.py +51 -3
  76. package/mcp_server/song_brain/builder.py +47 -5
  77. package/mcp_server/song_brain/tools.py +21 -7
  78. package/mcp_server/sound_design/critics.py +1 -0
  79. package/mcp_server/splice_client/client.py +117 -33
  80. package/mcp_server/splice_client/http_bridge.py +15 -3
  81. package/mcp_server/splice_client/quota.py +28 -0
  82. package/mcp_server/stuckness_detector/detector.py +8 -5
  83. package/mcp_server/synthesis_brain/adapters/drift.py +13 -0
  84. package/mcp_server/synthesis_brain/adapters/meld.py +13 -0
  85. package/mcp_server/tools/_analyzer_engine/sample.py +36 -10
  86. package/mcp_server/tools/_perception_engine.py +6 -0
  87. package/mcp_server/tools/agent_os.py +4 -1
  88. package/mcp_server/tools/analyzer.py +198 -209
  89. package/mcp_server/tools/arrangement.py +7 -4
  90. package/mcp_server/tools/automation.py +24 -4
  91. package/mcp_server/tools/browser.py +25 -11
  92. package/mcp_server/tools/clips.py +6 -0
  93. package/mcp_server/tools/composition.py +33 -2
  94. package/mcp_server/tools/devices.py +53 -53
  95. package/mcp_server/tools/generative.py +14 -14
  96. package/mcp_server/tools/harmony.py +7 -7
  97. package/mcp_server/tools/mixing.py +4 -4
  98. package/mcp_server/tools/planner.py +68 -6
  99. package/mcp_server/tools/research.py +20 -2
  100. package/mcp_server/tools/theory.py +10 -10
  101. package/mcp_server/tools/transport.py +7 -2
  102. package/mcp_server/transition_engine/critics.py +13 -1
  103. package/mcp_server/user_corpus/tools.py +30 -1
  104. package/mcp_server/wonder_mode/engine.py +82 -9
  105. package/mcp_server/wonder_mode/session.py +32 -10
  106. package/mcp_server/wonder_mode/tools.py +14 -1
  107. package/package.json +1 -1
  108. package/remote_script/LivePilot/__init__.py +21 -8
  109. package/remote_script/LivePilot/arrangement.py +93 -33
  110. package/remote_script/LivePilot/browser.py +60 -4
  111. package/remote_script/LivePilot/devices.py +132 -62
  112. package/remote_script/LivePilot/mixing.py +31 -5
  113. package/remote_script/LivePilot/server.py +94 -22
  114. package/remote_script/LivePilot/tracks.py +11 -5
  115. package/remote_script/LivePilot/transport.py +11 -0
  116. package/requirements.txt +5 -5
  117. package/server.json +2 -2
@@ -1,4 +1,4 @@
1
- # LivePilot v1.27.1 — Architecture & Tool Reference
1
+ # LivePilot v1.27.3 — Architecture & Tool Reference
2
2
 
3
3
  Agentic production system for Ableton Live 12. 467 tools across 56 domains. Device atlas (5264 devices, 120 enriched, 47 with aesthetic-tagged `signature_techniques`), spectral perception (M4L analyzer with 9-band FFT — sub_low / sub / low / low_mid / mid / high_mid / high / presence / air), technique memory, automation intelligence (16 curve types, 15 recipes), music theory (Krumhansl-Schmuckler, species counterpoint), generative algorithms (Euclidean rhythm, tintinnabuli, phase shift, additive process), neo-Riemannian harmony (PRL transforms, Tonnetz), MIDI file I/O, **LIVE Splice describe-a-sound + variations via captured GraphQL endpoints (v1.17)**, drum-rack pad-by-pad construction, live dead-device detection via meter sampling, role-aware Simpler defaults, session-record arrangement-automation workaround.
4
4
 
@@ -44,9 +44,16 @@ A flat tool list lets the AI press buttons. LivePilot's three layers give it con
44
44
 
45
45
  This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spectrum to confirm the mud is actually reduced."
46
46
 
47
- ## The 467 Tools What Each One Does
47
+ ## Core-Domain Reference (~228 tools, 13 of 56 domains)
48
48
 
49
- ### Transport (12) Playback, tempo, global state, diagnostics
49
+ This section documents the 13 highest-traffic domains in prose (what each
50
+ tool does, when to reach for it). It is intentionally NOT exhaustive — the
51
+ remaining domains (sample_engine, atlas, agent_os, wonder_mode, and the rest
52
+ of the Creative Intelligence layer) are covered by their own domain skills
53
+ and by the auto-generated **[Tool Catalog](../../../../docs/manual/tool-catalog.md)**,
54
+ which lists all 467 tools across all 56 domains.
55
+
56
+ ### Transport (showing 12 of 21) — Playback, tempo, global state, diagnostics
50
57
 
51
58
  | Tool | What it does | Key params |
52
59
  |------|-------------|------------|
@@ -63,7 +70,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
63
70
  | `get_recent_actions` | Returns log of recent commands sent to Ableton (newest first) | `limit` (1-50, default 20) |
64
71
  | `get_session_diagnostics` | Analyzes session for issues: armed tracks, solo leftovers, unnamed tracks, empty clips | — |
65
72
 
66
- ### Tracks (14) — Create, delete, configure, group tracks
73
+ ### Tracks (showing 14 of 21) — Create, delete, configure, group tracks
67
74
 
68
75
  | Tool | What it does | Key params |
69
76
  |------|-------------|------------|
@@ -82,7 +89,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
82
89
  | `set_group_fold` | Folds/unfolds a group track | `track_index`, `folded` (bool) |
83
90
  | `set_track_input_monitoring` | Sets input monitoring state | `track_index`, `state` (0=In, 1=Auto, 2=Off) |
84
91
 
85
- ### Clips (11) — Clip lifecycle, properties, warp
92
+ ### Clips (showing 11 of 16) — Clip lifecycle, properties, warp
86
93
 
87
94
  | Tool | What it does | Key params |
88
95
  |------|-------------|------------|
@@ -122,7 +129,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
122
129
  - `velocity_deviation` — -127.0 to 127.0
123
130
  - `release_velocity` — 0.0-127.0
124
131
 
125
- ### Devices (15) — Instruments, effects, racks, 12.3+ device insertion
132
+ ### Devices (showing 15 of 42) — Instruments, effects, racks, 12.3+ device insertion
126
133
 
127
134
  | Tool | What it does | Key params |
128
135
  |------|-------------|------------|
@@ -142,7 +149,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
142
149
  | `set_chain_volume` | Sets volume of a rack chain | `track_index`, `device_index`, `chain_index`, `volume` |
143
150
  | `get_device_presets` | Lists presets for a device (audio effects, instruments, MIDI effects) | `device_name` |
144
151
 
145
- ### Scenes (8) — Scene management
152
+ ### Scenes (showing 8 of 12) — Scene management
146
153
 
147
154
  | Tool | What it does | Key params |
148
155
  |------|-------------|------------|
@@ -180,7 +187,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
180
187
  | `search_browser` | Searches the browser | `query` |
181
188
  | `load_browser_item` | Loads a browser item onto a track — **`uri` MUST come from `search_browser` results, NEVER invented** | `track_index`, `uri` |
182
189
 
183
- ### Arrangement (20) — Timeline, recording, cue points, arrangement notes
190
+ ### Arrangement (showing 20 of 21) — Timeline, recording, cue points, arrangement notes
184
191
 
185
192
  | Tool | What it does | Key params |
186
193
  |------|-------------|------------|
@@ -205,7 +212,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
205
212
  | `jump_to_cue` | Jumps to a cue point by index | `cue_index` |
206
213
  | `toggle_cue_point` | Creates/removes cue point at current position | — |
207
214
 
208
- ### Memory (8) — Technique library persistence
215
+ ### Memory (showing 8 of 18) — Technique library persistence
209
216
 
210
217
  | Tool | What it does | Key params |
211
218
  |------|-------------|------------|
@@ -218,7 +225,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
218
225
  | `memory_update` | Updates name, tags, or qualities | `technique_id`, `name`, `tags`, `qualities` |
219
226
  | `memory_delete` | Removes technique (backs up first) | `technique_id` |
220
227
 
221
- ### Analyzer (38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
228
+ ### Analyzer (showing 20 of 38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
222
229
 
223
230
  | Tool | What it does | Key params |
224
231
  |------|-------------|------------|
@@ -243,7 +250,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
243
250
  | `stop_scrub` | Stop preview | `track_index`, `clip_index` |
244
251
  | `get_display_values` | Human-readable parameter values ("440 Hz", "-6 dB") | `track_index`, `device_index` |
245
252
 
246
- ### Automation (8) — Clip automation CRUD + intelligent curve generation
253
+ ### Automation (showing 8 of 9) — Clip automation CRUD + intelligent curve generation
247
254
 
248
255
  | Tool | What it does | Key params |
249
256
  |------|-------------|------------|
@@ -0,0 +1,125 @@
1
+ # Perception (Analyzer) Reference
2
+
3
+ Deep-dive detail for `mcp_server/tools/analyzer.py` tools. The tool
4
+ docstrings carry a trimmed operational contract (params, ranges,
5
+ gotchas); this file carries the full band tables, classification
6
+ thresholds, and historical bug context that motivated each behavior.
7
+ Read this before deep spectral/health-check work — the tool docstrings
8
+ point back here for the parts that don't change from call to call.
9
+
10
+ ## `get_master_spectrum` — 9-band table
11
+
12
+ Band energies (fffb~ center frequencies shown in parens), values 0.0-1.0:
13
+
14
+ | Band | Range | Center | Use |
15
+ |---|---|---|---|
16
+ | sub_low | 20-60 Hz | ~35 Hz | kick fundamentals, deep sub-bass |
17
+ | sub | 60-120 Hz | ~85 Hz | 808s, sub-bass body |
18
+ | low | 120-250 Hz | ~175 Hz | bass body, warmth |
19
+ | low_mid | 250-500 Hz | ~350 Hz | mud zone, male vocal lows |
20
+ | mid | 500 Hz-1 kHz | ~700 Hz | vocal presence, snare body |
21
+ | high_mid | 1-2 kHz | ~1.4 kHz | consonants, pick attack |
22
+ | high | 2-4 kHz | ~2.8 kHz | presence, vocal intelligibility |
23
+ | presence | 4-8 kHz | ~5.6 kHz | cymbal definition, air of breath |
24
+ | air | 8-20 kHz | ~12 kHz | shimmer, sparkle |
25
+
26
+ Older `.amxd` builds (pre-v1.16) emit the legacy 8-band layout without
27
+ the explicit `sub_low` split — the server auto-detects band count from
28
+ the OSC payload and picks the right name set. Re-freeze the Max device
29
+ to get the 9-band resolution.
30
+
31
+ **BUG-2026-04-22#6 fix — windowed averaging.** Kick transients make
32
+ single snapshots swing wildly (0.45 → 0.05 → 0.16 within a bar). The
33
+ `window_ms` param samples the cache over a time window and mean-pools
34
+ instead of returning one instantaneous frame.
35
+
36
+ **BUG-2026-04-22#15 fix — sub-band resolution.** `sub_detail=True`
37
+ derives three finer buckets from the FluCoMa 40-band mel spectrum
38
+ (band 0-1 ≈ sub_deep 0-45 Hz — kick fundamental, band 2 ≈ sub_mid
39
+ 45-60 Hz — 808 body/kick upper, band 3 ≈ sub_high 60-80 Hz — bass
40
+ guitar low/sub-bass crossover). Mel band edges are perceptual, not
41
+ linear Hz, so these are approximations tight enough for mixing
42
+ decisions ("is energy in the 30 Hz or 60 Hz range?"). Requires FluCoMa
43
+ active — omitted with `sub_detail_warning` otherwise.
44
+
45
+ ## `verify_device_health` / `verify_all_devices_health`
46
+
47
+ **BUG-2026-04-22#19 fix.** `parameter_count` alone can't tell you
48
+ whether an AU/VST is alive — plenty of "loaded" plugins return N
49
+ params and silence. These tools fire a real test MIDI note and read
50
+ the track meter across a window (`get_track_meters(samples=N)` to
51
+ dodge the BUG-#7 "left=right=0 while level>0" artifact).
52
+
53
+ Common dead-device causes (surfaced in the `hint` field when
54
+ `alive=False`): (1) plugin waiting for preset/bank selection, (2)
55
+ algorithm/envelope configured for zero output, (3) wrong MIDI channel
56
+ or velocity curve, (4) dead VST (reinstall). Try opening the device UI
57
+ and auditioning manually.
58
+
59
+ `verify_all_devices_health` (BUG-2026-04-26#1 fix): audio-track
60
+ detection uses `has_midi_input`/`has_audio_input` from
61
+ `get_session_info` (earlier code checked nonexistent `is_audio_track`/
62
+ `type` fields, so detection silently always evaluated False).
63
+ Empty-track detection requires a `get_track_info` round-trip per track
64
+ because `get_session_info` doesn't embed per-track `devices` arrays.
65
+
66
+ ## `classify_simpler_slices` — classification thresholds
67
+
68
+ Validated on "Break Ghosts 90 bpm" reference material:
69
+ - KICK: sub+low >= 45%, high < 40%
70
+ - HAT: high >= 70% AND mid < 25% (thin metal disc = no drum body)
71
+ - SNARE: mid >= 25% AND high >= 40% AND peak >= 0.6 (broadband loud)
72
+ - ghost: peak < 0.35
73
+
74
+ **Always run this before programming drum patterns on a sliced break.**
75
+ Slice content depends on transient detection order in the source
76
+ audio — slice 0 is NOT guaranteed to be a kick. Assuming drum-rack
77
+ convention produces wrong grooves that take iterations to diagnose.
78
+
79
+ File-path resolution order: explicit `file_path` param, then Remote
80
+ Script TCP (`get_simpler_file_path` via direct LOM read — most
81
+ reliable), then M4L bridge UDP fallback (kept registered for
82
+ environments where Remote Script is stale/unavailable; call
83
+ `reload_handlers` to refresh without a full restart).
84
+
85
+ ## `add_drum_rack_pad`
86
+
87
+ **BUG-2026-04-22#1 fix** — this tool closes a gap where
88
+ `load_browser_item` replaced the existing chain on repeat calls and
89
+ `load_sample_to_simpler` couldn't address nested rack paths. It chains
90
+ six steps atomically: locate/auto-detect the Drum Rack, insert a chain,
91
+ assign the trigger note, insert an empty Simpler into the chain, native
92
+ `replace_sample_native` with nested addressing, Snap=0 hygiene.
93
+
94
+ ## `replace_simpler_sample` / `load_sample_to_simpler`
95
+
96
+ Prefer `load_browser_item(track, uri)` when the file is browser-indexed
97
+ — the M4L bridge's replace path can silently keep the bootstrap
98
+ placeholder in some conditions (this is why both tools verify by
99
+ reading back the device name post-load and error if the replace didn't
100
+ actually take effect).
101
+
102
+ Nested addressing (`chain_index` + `nested_device_index`) is Live
103
+ 12.4+ only (BUG-#1, 2026-04-22) — resolves at
104
+ `track.devices[device_index].chains[chain_index].devices[nested_device_index or 0]`,
105
+ which is how Drum Rack pad-by-pad construction works. The M4L bridge
106
+ fallback cannot resolve nested paths; only the native 12.4 path honors
107
+ `chain_index`.
108
+
109
+ `load_sample_to_simpler`'s bootstrap flow (used pre-12.4 or when no
110
+ Simpler exists yet): loads a dummy sample via the browser to force
111
+ Ableton to create a Simpler, replaces it with the target file, then
112
+ runs the same post-load hygiene/verification as `replace_simpler_sample`.
113
+
114
+ ## `simpler_set_warp` / `compressor_set_sidechain` — LOM gap tools
115
+
116
+ **BUG-A2**: Python's Remote Script ControlSurface API can't reach
117
+ Simpler's `warping`/`warp_mode` — they live on the sample child object
118
+ (`SimplerDevice.sample.*`) that only Max for Live's JavaScript LiveAPI
119
+ can step into. Hence the M4L bridge round-trip.
120
+
121
+ **BUG-A3**: `compressor_set_sidechain`'s routing properties
122
+ (`sidechain_input_routing_type`/`_channel`) aren't in Compressor's
123
+ automatable parameter list, but Python's Remote Script reaches them
124
+ directly as device properties (same LOM pattern as `set_track_routing`)
125
+ — no M4L bridge needed here, unlike the warp case above.
@@ -0,0 +1,66 @@
1
+ # Device Parameter Units Reference
2
+
3
+ Full per-device unit table for `set_device_parameter` / `batch_set_parameters`
4
+ (`mcp_server/tools/devices.py`). The tool docstrings carry the most
5
+ commonly-hit gotchas inline; this file is the complete list plus the
6
+ bug history that motivated the error-enrichment behavior.
7
+
8
+ ## Parameter ranges are NOT always 0-1 (BUG-B4 / B9 / 2026-04-26#2)
9
+
10
+ Ableton devices use MIXED units depending on the parameter. Always read
11
+ the `value_string` in the response (and `min`/`max` from
12
+ `get_device_parameters`) before assuming 0-1 semantics:
13
+
14
+ - Auto Filter `Frequency`: 20-135 index (NOT normalized)
15
+ - Auto Filter Legacy `LFO Amount`: 0-30 absolute (displays as %)
16
+ - Auto Filter `Resonance`: 0-1.25 on legacy, 0-1 on AutoFilter2
17
+ - Auto Filter `Env. Modulation`: -127..+127 on legacy
18
+ - Compressor I (legacy): pre-2010 units (Threshold dB direct)
19
+ - **Compressor 2 (modern, default)**: 0-1 NORMALIZED. `Threshold 0.85 ≈
20
+ 0 dB`, `Ratio 0.75 = 4:1`, `Release 0.16 = 30 ms`. Setting Threshold
21
+ to a dB value like -22 will fail. Compute normalized: `(dB + 50) / 50`
22
+ for typical dB→0-1 mapping, OR read the param's `value_string` after
23
+ a probe write.
24
+ - **Saturator** `Drive`, `Output`, `Threshold`, `Color *`: 0-1
25
+ NORMALIZED (Drive 0.5 ≈ 0 dB, Drive 0.6 ≈ +7 dB).
26
+ - Dynamic Tube, Vocoder: pre-2010 units
27
+ - EQ Three `Frequency Hi/Lo`: 50Hz-15kHz absolute
28
+ - Wavetable `Osc 1 Pos`: 0-1 normalized ✓
29
+ - Drift / Analog / Operator macros: 0-1 normalized ✓
30
+ - Pedal `Output`: -20..+20 dB direct
31
+ - Pedal `Bass / Mid / Treble`: -1..+1 direct
32
+
33
+ ## Error enrichment (BUG-2026-04-26#2)
34
+
35
+ If the Remote Script rejects the value as out-of-range,
36
+ `set_device_parameter` fetches the parameter's actual
37
+ min/max/value_string and re-raises with that context inline — saves a
38
+ follow-up `get_device_parameters` round-trip in the agent loop after
39
+ every miss.
40
+
41
+ ## Silent snapping (BUG #4, v1.20.2)
42
+
43
+ Quantized-enum params (e.g. Beat Repeat's "Gate" at an integer enum)
44
+ silently snap a caller's float request to the nearest step. Both
45
+ `set_device_parameter` (via the `snapped` field) and
46
+ `batch_set_parameters` (via `snapped_params`, tolerance 1e-5) surface
47
+ this so callers driving deterministic state don't mistake a snap for
48
+ success. `batch_set_parameters` accepts any of `parameter_index`,
49
+ `parameter_name`, `name`, `index`, or the legacy `name_or_index` per
50
+ entry (BUG-F4 / BUG-2026-04-22#3 — the sibling tools originally had
51
+ inconsistent schemas, so all shapes are now normalized so
52
+ `get_device_parameters`'s output can be fed straight back in).
53
+
54
+ ## Drum Rack construction workflow (12.3+)
55
+
56
+ Shared by `insert_device`, `insert_rack_chain`, and the atomic
57
+ `add_drum_rack_pad` (see `perception.md` for that one's full history):
58
+
59
+ 1. `insert_device(track_index, 'Drum Rack')` — create empty rack
60
+ 2. `insert_rack_chain(track_index, device_index)` — add a chain
61
+ 3. `set_drum_chain_note(chain_index, note=36)` — assign C1 (kick)
62
+ 4. `insert_device(track_index, 'Simpler', device_index=rack_idx,
63
+ chain_index=0)` — add the instrument into that chain
64
+
65
+ On Live < 12.3, `insert_device`/`insert_rack_chain` return an error
66
+ suggesting `find_and_load_device` instead.
@@ -173,7 +173,7 @@ Live 12.4 introduces a new capability tier that unlocks native LOM access for sa
173
173
  **Tool signatures:** unchanged. Callers do not need to detect the tier —
174
174
  routing is transparent.
175
175
 
176
- **Probe-first 12.4 surfaces in v1.27.1:**
176
+ **Probe-first 12.4 surfaces in v1.27.3:**
177
177
  - `probe_link_audio()` reports observed peer/input/routing visibility and
178
178
  returns `manual_only`, `readable`, `routable`, or `unavailable`.
179
179
  - `probe_stem_workflow()` reports observed callable paths and returns
@@ -27,6 +27,14 @@ If the M4L analyzer bridge is absent, critics fall back to role-based heuristics
27
27
 
28
28
  For detailed frequency collision data, call `get_masking_report`. For a quick status overview without the full critic pass, call `get_mix_summary`.
29
29
 
30
+ Each masking entry carries `measured` and `severity_basis`: `measured=True` /
31
+ `severity_basis="spectral_overlap"` means `severity` came from real per-track
32
+ spectral data; `measured=False` / `severity_basis="role_heuristic"` means it's
33
+ a role-pair prior with no per-track measurement behind it. Treat
34
+ `measured=False` entries as low-confidence hypotheses, not verified problems —
35
+ solo the pair and read `get_master_spectrum` before acting on them. See
36
+ `livepilot-core` SKILL.md → "Response Fields You Must Check".
37
+
30
38
  ### Step 2 — Plan
31
39
 
32
40
  Pick the highest-severity issue from the `issues` array. Call `plan_mix_move` with the issue data. The planner returns the smallest intervention that addresses the problem — a single parameter change, not a chain of edits.
@@ -31,7 +31,7 @@ Run this checklist EVERY time the user says "update everything", "push", "releas
31
31
  Current: **467 tools across 56 domains**.
32
32
  Spectral/analyzer (bridge-only): **38**. The remaining tool surface works without the bridge or degrades gracefully. Backed by 32 bridge commands.
33
33
 
34
- Verify: `grep -rc "@mcp.tool" mcp_server/tools/ | grep -v ":0" | awk -F: '{sum+=$2} END{print sum}'`
34
+ Verify: `python3 scripts/sync_metadata.py --check`
35
35
 
36
36
  Files that reference tool count:
37
37
  - [ ] `README.md` — header ("467 tools. 56 domains"), bridge section ("38 spectral/analyzer tools require bridge")
@@ -0,0 +1,56 @@
1
+ # Splice Tool Notes
2
+
3
+ Implementation history and worked examples for the Splice-facing tools
4
+ in `mcp_server/sample_engine/tools.py`. The tool docstrings carry the
5
+ operational contract (params, return shape, gating rules); this file
6
+ carries endpoint-capture history and full response examples.
7
+
8
+ ## `get_splice_credits` — full response example (Ableton Live plan)
9
+
10
+ ```json
11
+ {
12
+ "connected": true,
13
+ "username": "user-1367453956",
14
+ "plan_raw": "subscribed",
15
+ "plan_kind": "ableton_live",
16
+ "sounds_plan_id": 12,
17
+ "features": {"ableton_unmetered": true},
18
+ "credits_remaining": 80,
19
+ "credit_floor": 5,
20
+ "daily_quota": {
21
+ "used_today": 3, "remaining_today": 97, "daily_limit": 100,
22
+ "near_limit": false, "at_limit": false
23
+ },
24
+ "can_download_sample": true,
25
+ "download_gating": "daily_quota"
26
+ }
27
+ ```
28
+
29
+ `download_gating` is `"daily_quota"` on the Ableton Live plan (the
30
+ 100/day unmetered quota) or `"credit_floor"` on Sounds+/Creator/
31
+ Creator+ plans (the `CREDIT_HARD_FLOOR` protects the last 5 credits).
32
+ `connected: false` with zero credits means the Splice desktop app isn't
33
+ running or `grpcio` isn't installed.
34
+
35
+ ## `splice_describe_sound` / `splice_generate_variation` — endpoint history
36
+
37
+ Both hit GraphQL operations on `surfaces-graphql.splice.com`, captured
38
+ via mitmproxy against Splice desktop 5.4.9 + the Sounds Plugin
39
+ (status: LIVE as of 2026-04-22):
40
+
41
+ - `splice_describe_sound` → `SamplesSearch` with `semantic=1` +
42
+ `rephrase=true`. This is the Sounds Plugin's "Describe a Sound"
43
+ feature — Splice's AI matches free-form descriptions like "dark
44
+ ambient pad with shimmer" to catalog samples.
45
+ - `splice_generate_variation` → `AssetSimilarSoundsQuery` (the
46
+ right-click "Variations" menu item). Up to 10 results, no credit
47
+ cost — despite the tool name, this is a similarity-recommender
48
+ lookup, not AI audio synthesis (the "generate" naming in the original
49
+ handoff spec was aspirational).
50
+
51
+ Both tools strip the raw GraphQL response before returning (~270KB of
52
+ noise per call) — only the flattened sample list ships back.
53
+
54
+ `splice_search_with_sound` was removed 2026-04-22 — the user does this
55
+ in-Splice manually. The capture recipe for resurrecting it is at
56
+ `docs/2026-04-22-splice-https-capture-recipe.md`.
@@ -111,6 +111,12 @@ Wonder Mode now serves two callers:
111
111
  references/move-family-diversity-rule.md)
112
112
  - 1 executable + 2 analytical is an honest, useful result
113
113
  - The `variant_count_actual` field tells you how many are real
114
+ - **Check `degraded_reason`** on every `enter_wonder_mode` response — when
115
+ non-empty, fewer than 3 variants are actually executable (or none matched
116
+ and the set is cold-start fallback). Do not present a degraded set as
117
+ "three genuinely different options"; surface the degradation to the user
118
+ in the same terms the field describes. See `livepilot-core` SKILL.md →
119
+ "Response Fields You Must Check".
114
120
 
115
121
  ## Presenting Results
116
122
 
Binary file
@@ -34,7 +34,7 @@ outlets = 2; // 0: to udpsend (responses), 1: to buffer~/status
34
34
  // Single source of truth for the bridge version — bumped alongside the
35
35
  // rest of the release manifest. Surfaced in the UI via messnamed("livepilot_version", ...)
36
36
  // so the frozen .amxd visibly reports which build it was last exported from.
37
- var VERSION = "1.27.1";
37
+ var VERSION = "1.27.3";
38
38
 
39
39
  // ── State ──────────────────────────────────────────────────────────────────
40
40
 
@@ -45,6 +45,7 @@ var pitch_history = []; // Rolling buffer for key detection
45
45
  var MAX_PITCH_HISTORY = 128;
46
46
  var detected_key = "";
47
47
  var detected_scale = "";
48
+ var current_response_request_id = "";
48
49
 
49
50
  // Capture state
50
51
  var capture_active = false;
@@ -85,9 +86,19 @@ function anything() {
85
86
  var cmd = messagename;
86
87
  if (cmd.charAt(0) === "/") cmd = cmd.substring(1);
87
88
  var args = _decode_arg_strings(arrayfromargs(arguments));
89
+ var request_id = "";
90
+ if (args.length > 0 && typeof args[args.length - 1] === "string") {
91
+ var last_arg = args[args.length - 1];
92
+ var request_prefix = "__livepilot_request_id:";
93
+ if (last_arg.indexOf(request_prefix) === 0) {
94
+ request_id = last_arg.substring(request_prefix.length);
95
+ args.pop();
96
+ }
97
+ }
88
98
 
89
99
  // Defer to low-priority thread for LiveAPI safety
90
100
  var task = new Task(function() {
101
+ current_response_request_id = request_id;
91
102
  try {
92
103
  dispatch(cmd, args);
93
104
  } catch(e) {
@@ -223,6 +234,11 @@ function cmd_get_params(args) {
223
234
 
224
235
  var batch_size = 8;
225
236
  var current = 0;
237
+ // Capture the request id now: read_batch reschedules itself via
238
+ // Task.schedule(20), and an interleaved command arriving in that gap can
239
+ // overwrite the module-level current_response_request_id before the final
240
+ // send_response fires. The closure keeps OUR id stable across batches.
241
+ var captured_request_id = current_response_request_id;
226
242
 
227
243
  function read_batch() {
228
244
  try {
@@ -246,7 +262,7 @@ function cmd_get_params(args) {
246
262
  var next_task = new Task(read_batch);
247
263
  next_task.schedule(20);
248
264
  } else {
249
- send_response({"track": track_idx, "device": device_idx, "params": params});
265
+ send_response({"track": track_idx, "device": device_idx, "params": params}, captured_request_id);
250
266
  }
251
267
  } catch (e) {
252
268
  send_response({
@@ -254,7 +270,7 @@ function cmd_get_params(args) {
254
270
  "track": track_idx,
255
271
  "device": device_idx,
256
272
  "partial_params": params
257
- });
273
+ }, captured_request_id);
258
274
  }
259
275
  }
260
276
 
@@ -275,6 +291,9 @@ function cmd_get_hidden_params(args) {
275
291
  var params = [];
276
292
  var current = 0;
277
293
  var batch_size = 8;
294
+ // See cmd_get_params: capture the request id so the closure survives the
295
+ // Task.schedule(20) gaps without being clobbered by an interleaved command.
296
+ var captured_request_id = current_response_request_id;
278
297
 
279
298
  function read_batch() {
280
299
  try {
@@ -307,7 +326,7 @@ function cmd_get_hidden_params(args) {
307
326
  "device_name": device_name,
308
327
  "total_params": param_count,
309
328
  "params": params
310
- });
329
+ }, captured_request_id);
311
330
  }
312
331
  } catch (e) {
313
332
  send_response({
@@ -316,7 +335,7 @@ function cmd_get_hidden_params(args) {
316
335
  "device": device_idx,
317
336
  "device_name": device_name,
318
337
  "partial_params": params
319
- });
338
+ }, captured_request_id);
320
339
  }
321
340
  }
322
341
 
@@ -334,6 +353,9 @@ function cmd_get_auto_state(args) {
334
353
  var results = [];
335
354
  var current = 0;
336
355
  var batch_size = 8;
356
+ // See cmd_get_params: capture the request id so the closure survives the
357
+ // Task.schedule(20) gaps without being clobbered by an interleaved command.
358
+ var captured_request_id = current_response_request_id;
337
359
 
338
360
  function read_batch() {
339
361
  try {
@@ -362,7 +384,7 @@ function cmd_get_auto_state(args) {
362
384
  "total_params": param_count,
363
385
  "automated_params": results,
364
386
  "automated_count": results.length
365
- });
387
+ }, captured_request_id);
366
388
  }
367
389
  } catch (e) {
368
390
  send_response({
@@ -372,7 +394,7 @@ function cmd_get_auto_state(args) {
372
394
  "total_params": param_count,
373
395
  "automated_params": results,
374
396
  "automated_count": results.length
375
- });
397
+ }, captured_request_id);
376
398
  }
377
399
  }
378
400
 
@@ -689,22 +711,37 @@ function correlate(a, b) {
689
711
 
690
712
  // ── Response Encoding ──────────────────────────────────────────────────────
691
713
 
692
- function send_response(obj) {
693
- var json = JSON.stringify(obj);
714
+ function send_response(obj, explicit_id) {
715
+ var response = obj || {};
716
+ // Async/batched handlers (cmd_get_params et al.) capture the request id in
717
+ // a closure and pass it explicitly here, because the module-level
718
+ // current_response_request_id can be clobbered by an interleaved command
719
+ // that arrives during a Task.schedule() gap between batches.
720
+ var rid = (typeof explicit_id === "string" && explicit_id !== "")
721
+ ? explicit_id
722
+ : current_response_request_id;
723
+ if (rid) {
724
+ response._livepilot_request_id = rid;
725
+ }
726
+ var json = JSON.stringify(response);
694
727
  var encoded = base64_encode(json);
695
728
 
696
729
  // Check if chunking needed (Max OSC packet limit ~8KB)
697
730
  if (encoded.length < 1400) {
698
731
  outlet(0, "/response", encoded);
699
732
  } else {
700
- // Split into chunks
733
+ // Split into chunks. The request id rides the chunk header (first arg)
734
+ // so the Python side buckets chunks per-response and never mixes two
735
+ // commands' chunks — the id inside the JSON can't be read until the
736
+ // chunks are reassembled.
701
737
  var chunk_size = 1400;
702
738
  var total = Math.ceil(encoded.length / chunk_size);
703
739
  for (var i = 0; i < total; i++) {
704
740
  var piece = encoded.substring(i * chunk_size, (i + 1) * chunk_size);
705
- outlet(0, "/response_chunk", i, total, piece);
741
+ outlet(0, "/response_chunk", (rid || ""), i, total, piece);
706
742
  }
707
743
  }
744
+ current_response_request_id = "";
708
745
  }
709
746
 
710
747
  function base64_encode(str) {
@@ -1,2 +1,2 @@
1
1
  """LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
2
- __version__ = "1.27.1"
2
+ __version__ = "1.27.3"