livepilot 1.9.24 → 1.10.1

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 (185) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/AGENTS.md +3 -3
  3. package/CHANGELOG.md +223 -0
  4. package/CONTRIBUTING.md +2 -2
  5. package/LICENSE +62 -21
  6. package/README.md +291 -276
  7. package/bin/livepilot.js +87 -0
  8. package/installer/codex.js +147 -0
  9. package/livepilot/.Codex-plugin/plugin.json +2 -2
  10. package/livepilot/.claude-plugin/plugin.json +2 -2
  11. package/livepilot/skills/livepilot-arrangement/SKILL.md +18 -1
  12. package/livepilot/skills/livepilot-core/SKILL.md +22 -5
  13. package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +34 -0
  14. package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +204 -0
  15. package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +173 -0
  16. package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +211 -0
  17. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +188 -0
  18. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +162 -0
  19. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +229 -0
  20. package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +243 -0
  21. package/livepilot/skills/livepilot-core/references/overview.md +13 -9
  22. package/livepilot/skills/livepilot-core/references/sample-manipulation.md +724 -0
  23. package/livepilot/skills/livepilot-core/references/sound-design-deep.md +140 -0
  24. package/livepilot/skills/livepilot-devices/SKILL.md +39 -4
  25. package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
  26. package/livepilot/skills/livepilot-release/SKILL.md +23 -19
  27. package/livepilot/skills/livepilot-sample-engine/SKILL.md +105 -0
  28. package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +87 -0
  29. package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +51 -0
  30. package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +131 -0
  31. package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +45 -0
  32. package/livepilot/skills/livepilot-wonder/SKILL.md +17 -0
  33. package/livepilot.mcpb +0 -0
  34. package/m4l_device/livepilot_bridge.js +1 -1
  35. package/manifest.json +4 -4
  36. package/mcp_server/__init__.py +1 -1
  37. package/mcp_server/atlas/__init__.py +357 -0
  38. package/mcp_server/atlas/device_atlas.json +44067 -0
  39. package/mcp_server/atlas/enrichments/__init__.py +111 -0
  40. package/mcp_server/atlas/enrichments/audio_effects/auto_filter.yaml +162 -0
  41. package/mcp_server/atlas/enrichments/audio_effects/beat_repeat.yaml +183 -0
  42. package/mcp_server/atlas/enrichments/audio_effects/channel_eq.yaml +126 -0
  43. package/mcp_server/atlas/enrichments/audio_effects/chorus_ensemble.yaml +149 -0
  44. package/mcp_server/atlas/enrichments/audio_effects/color_limiter.yaml +109 -0
  45. package/mcp_server/atlas/enrichments/audio_effects/compressor.yaml +159 -0
  46. package/mcp_server/atlas/enrichments/audio_effects/convolution_reverb.yaml +143 -0
  47. package/mcp_server/atlas/enrichments/audio_effects/convolution_reverb_pro.yaml +178 -0
  48. package/mcp_server/atlas/enrichments/audio_effects/delay.yaml +151 -0
  49. package/mcp_server/atlas/enrichments/audio_effects/drum_buss.yaml +142 -0
  50. package/mcp_server/atlas/enrichments/audio_effects/dynamic_tube.yaml +147 -0
  51. package/mcp_server/atlas/enrichments/audio_effects/echo.yaml +167 -0
  52. package/mcp_server/atlas/enrichments/audio_effects/eq_eight.yaml +148 -0
  53. package/mcp_server/atlas/enrichments/audio_effects/eq_three.yaml +121 -0
  54. package/mcp_server/atlas/enrichments/audio_effects/erosion.yaml +103 -0
  55. package/mcp_server/atlas/enrichments/audio_effects/filter_delay.yaml +173 -0
  56. package/mcp_server/atlas/enrichments/audio_effects/gate.yaml +130 -0
  57. package/mcp_server/atlas/enrichments/audio_effects/gated_delay.yaml +133 -0
  58. package/mcp_server/atlas/enrichments/audio_effects/glue_compressor.yaml +142 -0
  59. package/mcp_server/atlas/enrichments/audio_effects/grain_delay.yaml +141 -0
  60. package/mcp_server/atlas/enrichments/audio_effects/hybrid_reverb.yaml +160 -0
  61. package/mcp_server/atlas/enrichments/audio_effects/limiter.yaml +97 -0
  62. package/mcp_server/atlas/enrichments/audio_effects/multiband_dynamics.yaml +174 -0
  63. package/mcp_server/atlas/enrichments/audio_effects/overdrive.yaml +119 -0
  64. package/mcp_server/atlas/enrichments/audio_effects/pedal.yaml +145 -0
  65. package/mcp_server/atlas/enrichments/audio_effects/phaser_flanger.yaml +161 -0
  66. package/mcp_server/atlas/enrichments/audio_effects/redux.yaml +114 -0
  67. package/mcp_server/atlas/enrichments/audio_effects/reverb.yaml +190 -0
  68. package/mcp_server/atlas/enrichments/audio_effects/roar.yaml +159 -0
  69. package/mcp_server/atlas/enrichments/audio_effects/saturator.yaml +146 -0
  70. package/mcp_server/atlas/enrichments/audio_effects/shifter.yaml +154 -0
  71. package/mcp_server/atlas/enrichments/audio_effects/spectral_resonator.yaml +141 -0
  72. package/mcp_server/atlas/enrichments/audio_effects/spectral_time.yaml +164 -0
  73. package/mcp_server/atlas/enrichments/audio_effects/vector_delay.yaml +140 -0
  74. package/mcp_server/atlas/enrichments/audio_effects/vinyl_distortion.yaml +141 -0
  75. package/mcp_server/atlas/enrichments/instruments/analog.yaml +222 -0
  76. package/mcp_server/atlas/enrichments/instruments/bass.yaml +202 -0
  77. package/mcp_server/atlas/enrichments/instruments/collision.yaml +150 -0
  78. package/mcp_server/atlas/enrichments/instruments/drift.yaml +167 -0
  79. package/mcp_server/atlas/enrichments/instruments/electric.yaml +137 -0
  80. package/mcp_server/atlas/enrichments/instruments/emit.yaml +163 -0
  81. package/mcp_server/atlas/enrichments/instruments/meld.yaml +164 -0
  82. package/mcp_server/atlas/enrichments/instruments/operator.yaml +197 -0
  83. package/mcp_server/atlas/enrichments/instruments/poli.yaml +192 -0
  84. package/mcp_server/atlas/enrichments/instruments/sampler.yaml +218 -0
  85. package/mcp_server/atlas/enrichments/instruments/simpler.yaml +217 -0
  86. package/mcp_server/atlas/enrichments/instruments/tension.yaml +156 -0
  87. package/mcp_server/atlas/enrichments/instruments/tree_tone.yaml +162 -0
  88. package/mcp_server/atlas/enrichments/instruments/vector_fm.yaml +165 -0
  89. package/mcp_server/atlas/enrichments/instruments/vector_grain.yaml +166 -0
  90. package/mcp_server/atlas/enrichments/instruments/wavetable.yaml +162 -0
  91. package/mcp_server/atlas/enrichments/midi_effects/arpeggiator.yaml +156 -0
  92. package/mcp_server/atlas/enrichments/midi_effects/bouncy_notes.yaml +93 -0
  93. package/mcp_server/atlas/enrichments/midi_effects/chord.yaml +147 -0
  94. package/mcp_server/atlas/enrichments/midi_effects/melodic_steps.yaml +97 -0
  95. package/mcp_server/atlas/enrichments/midi_effects/note_echo.yaml +108 -0
  96. package/mcp_server/atlas/enrichments/midi_effects/note_length.yaml +97 -0
  97. package/mcp_server/atlas/enrichments/midi_effects/pitch.yaml +76 -0
  98. package/mcp_server/atlas/enrichments/midi_effects/random.yaml +117 -0
  99. package/mcp_server/atlas/enrichments/midi_effects/rhythmic_steps.yaml +103 -0
  100. package/mcp_server/atlas/enrichments/midi_effects/scale.yaml +83 -0
  101. package/mcp_server/atlas/enrichments/midi_effects/step_arp.yaml +112 -0
  102. package/mcp_server/atlas/enrichments/midi_effects/velocity.yaml +119 -0
  103. package/mcp_server/atlas/enrichments/utility/amp.yaml +159 -0
  104. package/mcp_server/atlas/enrichments/utility/cabinet.yaml +109 -0
  105. package/mcp_server/atlas/enrichments/utility/corpus.yaml +150 -0
  106. package/mcp_server/atlas/enrichments/utility/resonators.yaml +131 -0
  107. package/mcp_server/atlas/enrichments/utility/spectrum.yaml +63 -0
  108. package/mcp_server/atlas/enrichments/utility/tuner.yaml +51 -0
  109. package/mcp_server/atlas/enrichments/utility/utility.yaml +136 -0
  110. package/mcp_server/atlas/enrichments/utility/vocoder.yaml +160 -0
  111. package/mcp_server/atlas/scanner.py +236 -0
  112. package/mcp_server/atlas/tools.py +224 -0
  113. package/mcp_server/composer/__init__.py +1 -0
  114. package/mcp_server/composer/engine.py +532 -0
  115. package/mcp_server/composer/layer_planner.py +427 -0
  116. package/mcp_server/composer/prompt_parser.py +329 -0
  117. package/mcp_server/composer/sample_resolver.py +153 -0
  118. package/mcp_server/composer/tools.py +211 -0
  119. package/mcp_server/connection.py +53 -8
  120. package/mcp_server/corpus/__init__.py +377 -0
  121. package/mcp_server/device_forge/__init__.py +1 -0
  122. package/mcp_server/device_forge/builder.py +377 -0
  123. package/mcp_server/device_forge/models.py +142 -0
  124. package/mcp_server/device_forge/templates.py +483 -0
  125. package/mcp_server/device_forge/tools.py +162 -0
  126. package/mcp_server/m4l_bridge.py +1 -0
  127. package/mcp_server/memory/taste_accessors.py +47 -0
  128. package/mcp_server/preview_studio/engine.py +9 -2
  129. package/mcp_server/preview_studio/tools.py +78 -35
  130. package/mcp_server/project_brain/tools.py +34 -0
  131. package/mcp_server/runtime/capability_probe.py +21 -2
  132. package/mcp_server/runtime/execution_router.py +184 -38
  133. package/mcp_server/runtime/live_version.py +102 -0
  134. package/mcp_server/runtime/mcp_dispatch.py +46 -0
  135. package/mcp_server/runtime/remote_commands.py +13 -5
  136. package/mcp_server/runtime/tools.py +66 -29
  137. package/mcp_server/sample_engine/__init__.py +1 -0
  138. package/mcp_server/sample_engine/analyzer.py +216 -0
  139. package/mcp_server/sample_engine/critics.py +390 -0
  140. package/mcp_server/sample_engine/models.py +193 -0
  141. package/mcp_server/sample_engine/moves.py +127 -0
  142. package/mcp_server/sample_engine/planner.py +186 -0
  143. package/mcp_server/sample_engine/slice_workflow.py +190 -0
  144. package/mcp_server/sample_engine/sources.py +540 -0
  145. package/mcp_server/sample_engine/techniques.py +908 -0
  146. package/mcp_server/sample_engine/tools.py +545 -0
  147. package/mcp_server/semantic_moves/__init__.py +3 -0
  148. package/mcp_server/semantic_moves/device_creation_moves.py +237 -0
  149. package/mcp_server/semantic_moves/mix_moves.py +8 -8
  150. package/mcp_server/semantic_moves/models.py +7 -7
  151. package/mcp_server/semantic_moves/performance_moves.py +4 -4
  152. package/mcp_server/semantic_moves/sample_compilers.py +377 -0
  153. package/mcp_server/semantic_moves/sound_design_moves.py +4 -4
  154. package/mcp_server/semantic_moves/tools.py +63 -10
  155. package/mcp_server/semantic_moves/transition_moves.py +4 -4
  156. package/mcp_server/server.py +71 -1
  157. package/mcp_server/session_continuity/tracker.py +4 -1
  158. package/mcp_server/sound_design/critics.py +89 -1
  159. package/mcp_server/splice_client/__init__.py +1 -0
  160. package/mcp_server/splice_client/client.py +347 -0
  161. package/mcp_server/splice_client/models.py +96 -0
  162. package/mcp_server/splice_client/protos/__init__.py +1 -0
  163. package/mcp_server/splice_client/protos/app_pb2.py +319 -0
  164. package/mcp_server/splice_client/protos/app_pb2.pyi +1153 -0
  165. package/mcp_server/splice_client/protos/app_pb2_grpc.py +1946 -0
  166. package/mcp_server/tools/_conductor.py +16 -0
  167. package/mcp_server/tools/_planner_engine.py +24 -0
  168. package/mcp_server/tools/analyzer.py +2 -0
  169. package/mcp_server/tools/arrangement.py +69 -0
  170. package/mcp_server/tools/automation.py +15 -2
  171. package/mcp_server/tools/devices.py +117 -6
  172. package/mcp_server/tools/notes.py +37 -4
  173. package/mcp_server/tools/planner.py +3 -0
  174. package/mcp_server/wonder_mode/diagnosis.py +5 -0
  175. package/mcp_server/wonder_mode/engine.py +144 -14
  176. package/mcp_server/wonder_mode/tools.py +33 -1
  177. package/package.json +14 -4
  178. package/remote_script/LivePilot/__init__.py +8 -1
  179. package/remote_script/LivePilot/arrangement.py +114 -0
  180. package/remote_script/LivePilot/browser.py +56 -1
  181. package/remote_script/LivePilot/devices.py +246 -6
  182. package/remote_script/LivePilot/mixing.py +8 -3
  183. package/remote_script/LivePilot/server.py +5 -1
  184. package/remote_script/LivePilot/transport.py +3 -0
  185. package/remote_script/LivePilot/version_detect.py +78 -0
@@ -0,0 +1,377 @@
1
+ """Compilers for sample-domain semantic moves.
2
+
3
+ These compile sample manipulation intents into concrete tool call sequences
4
+ using the session kernel to find appropriate tracks and devices.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from .compiler import CompiledPlan, CompiledStep, register_compiler
10
+ from .models import SemanticMove
11
+ from . import resolvers
12
+
13
+
14
+ def _resolve_sample_path(kernel: dict) -> str:
15
+ """Get the sample file path from kernel, or return placeholder."""
16
+ return kernel.get("sample_file_path", "{sample_file_path}")
17
+
18
+
19
+ def _compile_sample_chop_rhythm(move: SemanticMove, kernel: dict) -> CompiledPlan:
20
+ """Compile 'sample_chop_rhythm': load, slice, and chop a sample for rhythm."""
21
+ steps = []
22
+ descriptions = []
23
+ warnings = []
24
+
25
+ # Find drum/percussion tracks to layer alongside
26
+ drums = resolvers.find_tracks_by_role(kernel, ["drums", "percussion"])
27
+
28
+ # Create a new track for the chopped sample
29
+ steps.append(CompiledStep(
30
+ tool="create_midi_track",
31
+ params={"name": "Chop"},
32
+ description="Create track for chopped sample",
33
+ ))
34
+ descriptions.append("Create chop track")
35
+
36
+ # Load into Simpler — track index will be last + 1
37
+ tracks = kernel.get("session_info", {}).get("tracks", [])
38
+ new_idx = len(tracks)
39
+
40
+ steps.append(CompiledStep(
41
+ tool="load_sample_to_simpler",
42
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
43
+ description="Load sample into Simpler for slicing",
44
+ ))
45
+
46
+ steps.append(CompiledStep(
47
+ tool="set_simpler_playback_mode",
48
+ params={"track_index": new_idx, "device_index": 0, "playback_mode": 2},
49
+ description="Switch to slice mode for rhythmic chopping",
50
+ ))
51
+ descriptions.append("Slice sample")
52
+
53
+ # Balance against existing drums
54
+ if drums:
55
+ steps.append(CompiledStep(
56
+ tool="set_track_volume",
57
+ params={"track_index": new_idx, "volume": 0.55},
58
+ description="Set chop volume below main drums",
59
+ ))
60
+ else:
61
+ warnings.append("No drum tracks found — chop will be the primary rhythm")
62
+
63
+ steps.append(CompiledStep(
64
+ tool="get_track_meters",
65
+ params={"include_stereo": True},
66
+ description="Verify chopped sample producing audio",
67
+ ))
68
+
69
+ return CompiledPlan(
70
+ move_id=move.move_id,
71
+ intent=move.intent,
72
+ steps=steps,
73
+ risk_level="medium",
74
+ summary="; ".join(descriptions) if descriptions else "Chop sample for rhythm",
75
+ requires_approval=True,
76
+ warnings=warnings,
77
+ )
78
+
79
+
80
+ def _compile_sample_texture_layer(move: SemanticMove, kernel: dict) -> CompiledPlan:
81
+ """Compile 'sample_texture_layer': load and filter a sample as background texture."""
82
+ steps = []
83
+ descriptions = []
84
+
85
+ tracks = kernel.get("session_info", {}).get("tracks", [])
86
+ new_idx = len(tracks)
87
+
88
+ steps.append(CompiledStep(
89
+ tool="create_midi_track",
90
+ params={"name": "Texture"},
91
+ description="Create track for texture layer",
92
+ ))
93
+
94
+ steps.append(CompiledStep(
95
+ tool="load_sample_to_simpler",
96
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
97
+ description="Load textural sample into Simpler",
98
+ ))
99
+ descriptions.append("Load texture sample")
100
+
101
+ # Low volume for background placement
102
+ steps.append(CompiledStep(
103
+ tool="set_track_volume",
104
+ params={"track_index": new_idx, "volume": 0.35},
105
+ description="Set texture low in mix for background presence",
106
+ ))
107
+ descriptions.append("Set background level")
108
+
109
+ # Add reverb send for spatial depth
110
+ steps.append(CompiledStep(
111
+ tool="set_track_send",
112
+ params={"track_index": new_idx, "send_index": 0, "value": 0.40},
113
+ description="Heavy reverb for spatial depth on texture",
114
+ ))
115
+ descriptions.append("Add reverb depth")
116
+
117
+ steps.append(CompiledStep(
118
+ tool="get_track_meters",
119
+ params={"include_stereo": True},
120
+ description="Verify texture layer producing audio at low level",
121
+ ))
122
+
123
+ return CompiledPlan(
124
+ move_id=move.move_id,
125
+ intent=move.intent,
126
+ steps=steps,
127
+ risk_level="low",
128
+ summary="; ".join(descriptions),
129
+ requires_approval=(kernel.get("mode", "improve") != "explore"),
130
+ )
131
+
132
+
133
+ def _compile_sample_vocal_ghost(move: SemanticMove, kernel: dict) -> CompiledPlan:
134
+ """Compile 'sample_vocal_ghost': reverse, pitch, and wash a vocal sample."""
135
+ steps = []
136
+ descriptions = []
137
+
138
+ tracks = kernel.get("session_info", {}).get("tracks", [])
139
+ new_idx = len(tracks)
140
+
141
+ steps.append(CompiledStep(
142
+ tool="create_midi_track",
143
+ params={"name": "Ghost Vox"},
144
+ description="Create track for ghost vocal",
145
+ ))
146
+
147
+ steps.append(CompiledStep(
148
+ tool="load_sample_to_simpler",
149
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
150
+ description="Load vocal sample into Simpler",
151
+ ))
152
+
153
+ steps.append(CompiledStep(
154
+ tool="reverse_simpler",
155
+ params={"track_index": new_idx},
156
+ description="Reverse vocal for ghostly character",
157
+ ))
158
+ descriptions.append("Reverse vocal")
159
+
160
+ # Heavy reverb wash
161
+ steps.append(CompiledStep(
162
+ tool="set_track_send",
163
+ params={"track_index": new_idx, "send_index": 0, "value": 0.55},
164
+ description="Heavy reverb wash for ghostly depth",
165
+ ))
166
+ descriptions.append("Reverb wash")
167
+
168
+ # Low volume — ghosts live in the background
169
+ steps.append(CompiledStep(
170
+ tool="set_track_volume",
171
+ params={"track_index": new_idx, "volume": 0.30},
172
+ description="Set ghost vocal low in mix",
173
+ ))
174
+ descriptions.append("Background level")
175
+
176
+ steps.append(CompiledStep(
177
+ tool="get_track_meters",
178
+ params={"include_stereo": True},
179
+ description="Verify ghost vocal producing audio with reverb tail",
180
+ ))
181
+
182
+ return CompiledPlan(
183
+ move_id=move.move_id,
184
+ intent=move.intent,
185
+ steps=steps,
186
+ risk_level="medium",
187
+ summary="; ".join(descriptions),
188
+ requires_approval=True,
189
+ )
190
+
191
+
192
+ def _compile_sample_break_layer(move: SemanticMove, kernel: dict) -> CompiledPlan:
193
+ """Compile 'sample_break_layer': slice a break and layer over existing drums."""
194
+ steps = []
195
+ descriptions = []
196
+ warnings = []
197
+
198
+ drums = resolvers.find_tracks_by_role(kernel, ["drums", "percussion"])
199
+ if not drums:
200
+ warnings.append("No existing drum tracks — break will be the primary rhythm")
201
+
202
+ tracks = kernel.get("session_info", {}).get("tracks", [])
203
+ new_idx = len(tracks)
204
+
205
+ steps.append(CompiledStep(
206
+ tool="create_midi_track",
207
+ params={"name": "Break"},
208
+ description="Create track for breakbeat layer",
209
+ ))
210
+
211
+ steps.append(CompiledStep(
212
+ tool="load_sample_to_simpler",
213
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
214
+ description="Load breakbeat into Simpler",
215
+ ))
216
+
217
+ steps.append(CompiledStep(
218
+ tool="set_simpler_playback_mode",
219
+ params={"track_index": new_idx, "device_index": 0, "playback_mode": 2},
220
+ description="Slice break by transients for individual hits",
221
+ ))
222
+ descriptions.append("Slice break")
223
+
224
+ # Sit below main drums
225
+ steps.append(CompiledStep(
226
+ tool="set_track_volume",
227
+ params={"track_index": new_idx, "volume": 0.45},
228
+ description="Set break layer below main drums",
229
+ ))
230
+ descriptions.append("Balance break level")
231
+
232
+ steps.append(CompiledStep(
233
+ tool="get_track_meters",
234
+ params={"include_stereo": True},
235
+ description="Verify break layer producing audio alongside drums",
236
+ ))
237
+
238
+ return CompiledPlan(
239
+ move_id=move.move_id,
240
+ intent=move.intent,
241
+ steps=steps,
242
+ risk_level="medium",
243
+ summary="; ".join(descriptions) if descriptions else "Layer breakbeat",
244
+ requires_approval=True,
245
+ warnings=warnings,
246
+ )
247
+
248
+
249
+ def _compile_sample_resample_destroy(move: SemanticMove, kernel: dict) -> CompiledPlan:
250
+ """Compile 'sample_resample_destroy': warp and mangle a sample destructively.
251
+
252
+ SAFETY: This is a high-risk move — always requires approval.
253
+ Only adjusts device params when a known device is confirmed present.
254
+ """
255
+ steps = []
256
+ descriptions = []
257
+ warnings = ["High-risk: destructive processing — consider duplicating track first"]
258
+
259
+ tracks = kernel.get("session_info", {}).get("tracks", [])
260
+ new_idx = len(tracks)
261
+
262
+ steps.append(CompiledStep(
263
+ tool="create_midi_track",
264
+ params={"name": "Destroy"},
265
+ description="Create track for destructive resampling",
266
+ ))
267
+
268
+ steps.append(CompiledStep(
269
+ tool="load_sample_to_simpler",
270
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
271
+ description="Load sample for destruction",
272
+ ))
273
+ descriptions.append("Load source")
274
+
275
+ steps.append(CompiledStep(
276
+ tool="warp_simpler",
277
+ params={"track_index": new_idx},
278
+ description="Apply extreme warp for time-stretch artifacts",
279
+ ))
280
+ descriptions.append("Warp for artifacts")
281
+
282
+ # Use volume + send instead of blindly setting device params
283
+ steps.append(CompiledStep(
284
+ tool="set_track_send",
285
+ params={"track_index": new_idx, "send_index": 0, "value": 0.30},
286
+ description="Add reverb send for destroyed texture depth",
287
+ ))
288
+
289
+ steps.append(CompiledStep(
290
+ tool="set_track_volume",
291
+ params={"track_index": new_idx, "volume": 0.50},
292
+ description="Set destroyed sample at moderate level",
293
+ ))
294
+ descriptions.append("Set level")
295
+
296
+ steps.append(CompiledStep(
297
+ tool="get_track_meters",
298
+ params={"include_stereo": True},
299
+ description="Verify destroyed sample producing audio",
300
+ ))
301
+
302
+ return CompiledPlan(
303
+ move_id=move.move_id,
304
+ intent=move.intent,
305
+ steps=steps,
306
+ risk_level="high",
307
+ summary="; ".join(descriptions),
308
+ requires_approval=True,
309
+ warnings=warnings,
310
+ )
311
+
312
+
313
+ def _compile_sample_one_shot_accent(move: SemanticMove, kernel: dict) -> CompiledPlan:
314
+ """Compile 'sample_one_shot_accent': load a one-shot for rhythmic punctuation."""
315
+ steps = []
316
+ descriptions = []
317
+
318
+ tracks = kernel.get("session_info", {}).get("tracks", [])
319
+ new_idx = len(tracks)
320
+
321
+ steps.append(CompiledStep(
322
+ tool="create_midi_track",
323
+ params={"name": "Accent"},
324
+ description="Create track for one-shot accent",
325
+ ))
326
+
327
+ steps.append(CompiledStep(
328
+ tool="load_sample_to_simpler",
329
+ params={"track_index": new_idx, "file_path": _resolve_sample_path(kernel)},
330
+ description="Load one-shot into Simpler",
331
+ ))
332
+
333
+ steps.append(CompiledStep(
334
+ tool="set_simpler_playback_mode",
335
+ params={"track_index": new_idx, "device_index": 0, "playback_mode": 1},
336
+ description="One-shot mode for trigger playback",
337
+ ))
338
+ descriptions.append("One-shot mode")
339
+
340
+ steps.append(CompiledStep(
341
+ tool="crop_simpler",
342
+ params={"track_index": new_idx},
343
+ description="Tight crop around the transient",
344
+ ))
345
+ descriptions.append("Crop to transient")
346
+
347
+ # Accent should be punchy but not dominating
348
+ steps.append(CompiledStep(
349
+ tool="set_track_volume",
350
+ params={"track_index": new_idx, "volume": 0.60},
351
+ description="Set accent at punchy but balanced level",
352
+ ))
353
+
354
+ steps.append(CompiledStep(
355
+ tool="get_track_meters",
356
+ params={"include_stereo": True},
357
+ description="Verify one-shot accent triggers cleanly",
358
+ ))
359
+
360
+ return CompiledPlan(
361
+ move_id=move.move_id,
362
+ intent=move.intent,
363
+ steps=steps,
364
+ risk_level="low",
365
+ summary="; ".join(descriptions) if descriptions else "One-shot accent",
366
+ requires_approval=(kernel.get("mode", "improve") != "explore"),
367
+ )
368
+
369
+
370
+ # ── Register ────────────────────────────────────────────────────────────────
371
+
372
+ register_compiler("sample_chop_rhythm", _compile_sample_chop_rhythm)
373
+ register_compiler("sample_texture_layer", _compile_sample_texture_layer)
374
+ register_compiler("sample_vocal_ghost", _compile_sample_vocal_ghost)
375
+ register_compiler("sample_break_layer", _compile_sample_break_layer)
376
+ register_compiler("sample_resample_destroy", _compile_sample_resample_destroy)
377
+ register_compiler("sample_one_shot_accent", _compile_sample_one_shot_accent)
@@ -13,7 +13,7 @@ ADD_WARMTH = SemanticMove(
13
13
  targets={"warmth": 0.5, "depth": 0.3, "cohesion": 0.2},
14
14
  protect={"clarity": 0.6, "punch": 0.5},
15
15
  risk_level="low",
16
- compile_plan=[
16
+ plan_template=[
17
17
  {"tool": "set_device_parameter", "params": {"description": "Add Saturator drive +2-4dB for harmonic warmth"}, "description": "Add saturation", "backend": "remote_command"},
18
18
  {"tool": "set_device_parameter", "params": {"description": "Boost EQ low-mid shelf +1-2dB"}, "description": "Low-mid warmth", "backend": "remote_command"},
19
19
  ],
@@ -30,7 +30,7 @@ ADD_TEXTURE = SemanticMove(
30
30
  targets={"motion": 0.4, "novelty": 0.3, "depth": 0.3},
31
31
  protect={"clarity": 0.6},
32
32
  risk_level="medium",
33
- compile_plan=[
33
+ plan_template=[
34
34
  {"tool": "apply_automation_shape", "params": {"curve_type": "perlin", "description": "Perlin noise on filter cutoff for organic texture"}, "description": "Organic filter motion", "backend": "mcp_tool"},
35
35
  {"tool": "set_track_send", "params": {"description": "Increase delay send for spatial texture"}, "description": "Spatial texture via delay", "backend": "remote_command"},
36
36
  ],
@@ -46,7 +46,7 @@ SHAPE_TRANSIENTS = SemanticMove(
46
46
  targets={"punch": 0.5, "clarity": 0.3, "groove": 0.2},
47
47
  protect={"warmth": 0.5},
48
48
  risk_level="low",
49
- compile_plan=[
49
+ plan_template=[
50
50
  {"tool": "set_device_parameter", "params": {"description": "Adjust Compressor attack time (faster = sharper transients, slower = rounder)"}, "description": "Shape attack", "backend": "remote_command"},
51
51
  {"tool": "set_device_parameter", "params": {"description": "Adjust Compressor release for rhythmic pumping"}, "description": "Shape release", "backend": "remote_command"},
52
52
  ],
@@ -62,7 +62,7 @@ ADD_SPACE = SemanticMove(
62
62
  targets={"depth": 0.5, "width": 0.3, "clarity": 0.2},
63
63
  protect={"punch": 0.6, "clarity": 0.5},
64
64
  risk_level="low",
65
- compile_plan=[
65
+ plan_template=[
66
66
  {"tool": "set_track_send", "params": {"description": "Increase reverb send to 25-35%"}, "description": "Add reverb depth", "backend": "remote_command"},
67
67
  {"tool": "set_track_send", "params": {"description": "Add subtle delay send 10-15%"}, "description": "Add delay texture", "backend": "remote_command"},
68
68
  {"tool": "set_track_pan", "params": {"description": "Widen pan slightly for spatial presence"}, "description": "Widen spatial field", "backend": "remote_command"},
@@ -27,13 +27,15 @@ def list_semantic_moves(
27
27
  Semantic moves express WHAT to achieve musically, not HOW parametrically.
28
28
  Each move compiles into a sequence of existing deterministic tools.
29
29
 
30
- domain: filter by family (mix, arrangement, transition, sound_design, performance)
30
+ domain: filter by family (e.g. mix, arrangement, transition, sound_design, sample, performance)
31
31
  style: filter by genre/style (reserved for future use)
32
32
 
33
33
  Returns: list of moves with move_id, family, intent, targets, risk_level.
34
34
  """
35
35
  moves = registry.list_moves(domain=domain, style=style)
36
- return {"moves": moves, "count": len(moves), "available_domains": ["mix", "arrangement"]}
36
+ all_moves = registry.list_moves()
37
+ domains = sorted({m.get("family", "") for m in all_moves if m.get("family")})
38
+ return {"moves": moves, "count": len(moves), "available_domains": domains}
37
39
 
38
40
 
39
41
  @mcp.tool()
@@ -43,9 +45,13 @@ def preview_semantic_move(
43
45
  ) -> dict:
44
46
  """Preview what a semantic move will do before applying it.
45
47
 
46
- Returns the full compile plan (tool sequence), verification plan,
47
- targets, protection constraints, and risk level. Use this to understand
48
- the impact before committing.
48
+ Returns the static plan_template + verification_plans, PLUS an additive
49
+ compiled_plan field built by compiling the move against a lightweight
50
+ kernel of the current session. Use compiled_plan to inspect the concrete
51
+ tool calls the move would emit right now; use plan_template to understand
52
+ the move's shape independent of session state.
53
+
54
+ Existing callers reading plan_template are unaffected by the addition.
49
55
  """
50
56
  move = registry.get_move(move_id)
51
57
  if not move:
@@ -55,7 +61,46 @@ def preview_semantic_move(
55
61
  "available_moves": available,
56
62
  }
57
63
 
58
- return move.to_full_dict()
64
+ result = move.to_full_dict()
65
+
66
+ # Additive: compile against a lightweight kernel so callers get an
67
+ # executable representation alongside the static plan_template.
68
+ try:
69
+ from ..runtime.session_kernel import build_session_kernel
70
+ from ..runtime.capability_state import build_capability_state
71
+ from . import compiler as move_compiler
72
+
73
+ ableton = None
74
+ if hasattr(ctx, "lifespan_context"):
75
+ ableton = ctx.lifespan_context.get("ableton")
76
+
77
+ session_info: dict = {}
78
+ if ableton is not None:
79
+ try:
80
+ info = ableton.send_command("get_session_info")
81
+ if isinstance(info, dict):
82
+ session_info = info
83
+ except Exception:
84
+ session_info = {}
85
+
86
+ state = build_capability_state(
87
+ session_ok=bool(session_info),
88
+ analyzer_ok=False,
89
+ memory_ok=True,
90
+ )
91
+ kernel = build_session_kernel(
92
+ session_info=session_info,
93
+ capability_state=state.to_dict(),
94
+ )
95
+ plan = move_compiler.compile(move, kernel.to_dict())
96
+ result["compiled_plan"] = plan.to_dict()
97
+ result["compiled_plan_executable"] = bool(plan.executable)
98
+ except Exception as e:
99
+ result["compiled_plan"] = None
100
+ result["compiled_plan_executable"] = False
101
+ result["compiled_plan_error"] = str(e)
102
+
103
+ return result
59
104
 
60
105
 
61
106
  @mcp.tool()
@@ -124,7 +169,7 @@ def propose_next_best_move(
124
169
 
125
170
 
126
171
  @mcp.tool()
127
- def apply_semantic_move(
172
+ async def apply_semantic_move(
128
173
  ctx: Context,
129
174
  move_id: str,
130
175
  mode: str = "improve",
@@ -177,14 +222,22 @@ def apply_semantic_move(
177
222
  result["note"] = "Awaiting approval — present the plan to the user, then execute steps individually"
178
223
  return result
179
224
 
180
- # explore mode — execute through unified router
181
- from ..runtime.execution_router import execute_plan_steps
225
+ # explore mode — execute through the async router
226
+ from ..runtime.execution_router import execute_plan_steps_async
182
227
 
183
228
  step_dicts = [
184
229
  {"tool": step.tool, "params": step.params, "description": step.description}
185
230
  for step in plan.steps
186
231
  ]
187
- exec_results = execute_plan_steps(step_dicts, ableton=ableton, ctx=ctx)
232
+ bridge = ctx.lifespan_context.get("m4l")
233
+ mcp_registry = ctx.lifespan_context.get("mcp_dispatch", {})
234
+ exec_results = await execute_plan_steps_async(
235
+ step_dicts,
236
+ ableton=ableton,
237
+ bridge=bridge,
238
+ mcp_registry=mcp_registry,
239
+ ctx=ctx,
240
+ )
188
241
 
189
242
  executed_steps = []
190
243
  for i, er in enumerate(exec_results):
@@ -10,7 +10,7 @@ INCREASE_FORWARD_MOTION = SemanticMove(
10
10
  targets={"motion": 0.5, "energy": 0.3, "tension": 0.2},
11
11
  protect={"clarity": 0.6},
12
12
  risk_level="low",
13
- compile_plan=[
13
+ plan_template=[
14
14
  {"tool": "apply_automation_shape", "params": {"curve_type": "exponential", "description": "Rising filter cutoff over 4 bars"}, "description": "Rising filter sweep", "backend": "mcp_tool"},
15
15
  {"tool": "set_track_volume", "params": {"description": "Push rhythm elements +5-8%"}, "description": "Push rhythm forward", "backend": "remote_command"},
16
16
  {"tool": "apply_automation_shape", "params": {"curve_type": "linear", "description": "Rising reverb send for anticipation"}, "description": "Build reverb wash", "backend": "mcp_tool"},
@@ -27,7 +27,7 @@ OPEN_CHORUS = SemanticMove(
27
27
  targets={"energy": 0.4, "width": 0.3, "contrast": 0.3},
28
28
  protect={"clarity": 0.6, "cohesion": 0.5},
29
29
  risk_level="medium",
30
- compile_plan=[
30
+ plan_template=[
31
31
  {"tool": "set_track_volume", "params": {"description": "Push all melodic tracks +10-15%"}, "description": "Push chorus energy", "backend": "remote_command"},
32
32
  {"tool": "set_track_pan", "params": {"description": "Widen stereo field on chords/pads"}, "description": "Widen stereo", "backend": "remote_command"},
33
33
  {"tool": "set_track_send", "params": {"description": "Increase reverb/delay sends for spaciousness"}, "description": "Add space", "backend": "remote_command"},
@@ -45,7 +45,7 @@ CREATE_BREAKDOWN = SemanticMove(
45
45
  targets={"contrast": 0.5, "depth": 0.3, "clarity": 0.2},
46
46
  protect={"cohesion": 0.5},
47
47
  risk_level="medium",
48
- compile_plan=[
48
+ plan_template=[
49
49
  {"tool": "set_track_volume", "params": {"description": "Pull drums to 20-30%"}, "description": "Strip drums", "backend": "remote_command"},
50
50
  {"tool": "set_track_volume", "params": {"description": "Pull bass to 30-40%"}, "description": "Reduce bass", "backend": "remote_command"},
51
51
  {"tool": "set_track_send", "params": {"description": "Increase reverb send on remaining elements"}, "description": "Add reverb depth", "backend": "remote_command"},
@@ -62,7 +62,7 @@ BRIDGE_SECTIONS = SemanticMove(
62
62
  targets={"motion": 0.4, "contrast": 0.3, "cohesion": 0.3},
63
63
  protect={"clarity": 0.6},
64
64
  risk_level="low",
65
- compile_plan=[
65
+ plan_template=[
66
66
  {"tool": "apply_automation_shape", "params": {"curve_type": "cosine", "description": "Gentle filter sweep across bridge"}, "description": "Bridge filter motion", "backend": "mcp_tool"},
67
67
  {"tool": "set_track_volume", "params": {"description": "Gentle volume crossfade between section elements"}, "description": "Crossfade elements", "backend": "remote_command"},
68
68
  ],