livepilot 1.10.9 → 1.13.0

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 (61) hide show
  1. package/CHANGELOG.md +327 -0
  2. package/README.md +7 -7
  3. package/m4l_device/LivePilot_Analyzer.amxd +0 -0
  4. package/m4l_device/livepilot_bridge.js +1 -1
  5. package/mcp_server/__init__.py +1 -1
  6. package/mcp_server/branches/__init__.py +32 -0
  7. package/mcp_server/branches/types.py +230 -0
  8. package/mcp_server/composer/__init__.py +10 -1
  9. package/mcp_server/composer/branch_producer.py +229 -0
  10. package/mcp_server/evaluation/policy.py +129 -2
  11. package/mcp_server/experiment/engine.py +47 -11
  12. package/mcp_server/experiment/models.py +72 -7
  13. package/mcp_server/experiment/tools.py +231 -35
  14. package/mcp_server/m4l_bridge.py +488 -13
  15. package/mcp_server/memory/taste_graph.py +84 -11
  16. package/mcp_server/persistence/taste_store.py +21 -5
  17. package/mcp_server/runtime/execution_router.py +7 -0
  18. package/mcp_server/runtime/mcp_dispatch.py +32 -0
  19. package/mcp_server/runtime/remote_commands.py +54 -0
  20. package/mcp_server/runtime/session_kernel.py +46 -0
  21. package/mcp_server/runtime/tools.py +29 -3
  22. package/mcp_server/sample_engine/slice_classifier.py +169 -0
  23. package/mcp_server/server.py +11 -3
  24. package/mcp_server/synthesis_brain/__init__.py +53 -0
  25. package/mcp_server/synthesis_brain/adapters/__init__.py +34 -0
  26. package/mcp_server/synthesis_brain/adapters/analog.py +167 -0
  27. package/mcp_server/synthesis_brain/adapters/base.py +86 -0
  28. package/mcp_server/synthesis_brain/adapters/drift.py +166 -0
  29. package/mcp_server/synthesis_brain/adapters/meld.py +151 -0
  30. package/mcp_server/synthesis_brain/adapters/operator.py +169 -0
  31. package/mcp_server/synthesis_brain/adapters/wavetable.py +228 -0
  32. package/mcp_server/synthesis_brain/engine.py +91 -0
  33. package/mcp_server/synthesis_brain/models.py +121 -0
  34. package/mcp_server/synthesis_brain/timbre.py +194 -0
  35. package/mcp_server/tools/_conductor.py +144 -0
  36. package/mcp_server/tools/analyzer.py +187 -7
  37. package/mcp_server/tools/clips.py +65 -0
  38. package/mcp_server/tools/devices.py +517 -5
  39. package/mcp_server/tools/diagnostics.py +42 -0
  40. package/mcp_server/tools/follow_actions.py +202 -0
  41. package/mcp_server/tools/grooves.py +142 -0
  42. package/mcp_server/tools/miditool.py +280 -0
  43. package/mcp_server/tools/scales.py +126 -0
  44. package/mcp_server/tools/take_lanes.py +135 -0
  45. package/mcp_server/tools/tracks.py +46 -3
  46. package/mcp_server/tools/transport.py +62 -1
  47. package/mcp_server/wonder_mode/engine.py +324 -0
  48. package/mcp_server/wonder_mode/tools.py +153 -1
  49. package/package.json +2 -2
  50. package/remote_script/LivePilot/__init__.py +8 -4
  51. package/remote_script/LivePilot/clips.py +62 -0
  52. package/remote_script/LivePilot/devices.py +444 -0
  53. package/remote_script/LivePilot/diagnostics.py +52 -1
  54. package/remote_script/LivePilot/follow_actions.py +235 -0
  55. package/remote_script/LivePilot/grooves.py +185 -0
  56. package/remote_script/LivePilot/scales.py +138 -0
  57. package/remote_script/LivePilot/take_lanes.py +175 -0
  58. package/remote_script/LivePilot/tracks.py +59 -1
  59. package/remote_script/LivePilot/transport.py +90 -1
  60. package/remote_script/LivePilot/version_detect.py +9 -0
  61. package/server.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,332 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.13.0 — Branch-native architecture (April 20 2026)
4
+
5
+ Twelve-PR migration from "match request → pick move → compile move" to
6
+ "understand intent → generate branches → compile branches → compare".
7
+ The planning layer opens up — Wonder, Preview Studio, Experiment, and
8
+ the new synthesis_brain all share one BranchSeed + CompiledBranch
9
+ contract. Move-first is still available as a targeted flow; branch-native
10
+ is the canonical exploratory path.
11
+
12
+ **No tool count change** (still 398). **Domain count 51 → 52**
13
+ (added `synthesis_brain`). **+175 new tests** across 9 new files
14
+ (2206 → 2387 passing, 1 skipped, 0 failures).
15
+
16
+ ### New substrate (additive, non-breaking)
17
+
18
+ - **`mcp_server/branches/`** (PR1) — shared `BranchSeed` and
19
+ `CompiledBranch` types with `seed_from_move_id` / `freeform_seed` /
20
+ `analytical_seed` factories. `BranchSeed` sources:
21
+ `semantic_move` / `freeform` / `synthesis` / `composer` / `technique`.
22
+ - **SessionKernel creative controls** (PR2) — `freshness`,
23
+ `creativity_profile`, `sacred_elements`, `synth_hints` added as
24
+ optional fields on `SessionKernel` and `get_session_kernel`. Legacy
25
+ callers see zero behavior change.
26
+ - **ExperimentBranch compat shim** (PR3) — `move_id` now optional;
27
+ new `ExperimentBranch.from_seed()` classmethod and
28
+ `create_experiment_from_seeds(seeds=[...], compiled_plans=[...])`
29
+ entry point. Legacy `create_experiment(move_ids=...)` keeps working
30
+ and internally delegates via `seed_from_move_id`.
31
+ - **Creative conductor fork** (PR4) — `classify_request_creative()`
32
+ alongside `classify_request()`. Adds producer selection
33
+ (`branch_sources`, `seed_hints`) based on request content + kernel state.
34
+ - **`interesting_but_failed` branch status** (PR7) — new
35
+ `classify_branch_outcome()` in `evaluation/policy.py`. Exploration
36
+ mode downgrades score / measurable-delta failures to
37
+ `interesting_but_failed`; protection violations still force undo
38
+ (safety invariant).
39
+ - **Per-goal-mode novelty bands** (PR8) — TasteGraph's single
40
+ `novelty_band` is now a view over `novelty_bands["improve"]`; the
41
+ `explore` band lets surprise-me branch generation disconnect from
42
+ conservative improve-mode history. `bypass_taste_in_generation` flag
43
+ makes `rank_moves` return uniform scores.
44
+
45
+ ### Branch-native producers
46
+
47
+ - **Wonder branch assembler** (PR6) — `generate_branch_seeds()` emits
48
+ seeds from four sources: semantic_move, technique (session memory),
49
+ sacred-element inversion (freshness-gated), and corpus hints.
50
+ `enter_wonder_mode` now surfaces `branch_seeds` alongside variants.
51
+ - **`synthesis_brain/` subsystem** (PR9, PR10) — native-synth-aware
52
+ branch production with adapters for Wavetable, Operator, Analog,
53
+ Drift, Meld. `analyze_synth_patch()` / `propose_synth_branches()`
54
+ callable from Python; `extract_timbre_fingerprint()` builds a
55
+ TimbralFingerprint from 8-band spectrum + optional FluCoMa
56
+ descriptors. No MCP tools yet — next release will wire dedicated
57
+ tools and do the tool-count metadata sweep in one pass.
58
+ - **Composer branch producer** (PR11) — `propose_composer_branches()`
59
+ emits N distinct compositional hypotheses from one prompt via three
60
+ strategies (canonical / energy_shift / layer_contrast), gated on
61
+ freshness. Each branch ships a pre-compiled scaffolding plan.
62
+
63
+ ### Docs refactor
64
+
65
+ - **Skills + command guides thinned** (PR5) — `livepilot-core/SKILL.md`
66
+ now presents two peer flows (Flow A targeted / Flow B exploratory)
67
+ instead of one recipe-first pipeline. `arrange` / `beat` / `mix` /
68
+ `sounddesign` commands each add a short Branch-Native section.
69
+ - **Branch status vocabulary** documented including
70
+ `interesting_but_failed` retention semantics.
71
+
72
+ ### Migration notes for callers
73
+
74
+ - All additions are optional-param / new-function shaped. Any code
75
+ reading `branch.move_id` keeps working because `ExperimentBranch`
76
+ mirrors `seed.move_id` there. Any code calling
77
+ `create_experiment(move_ids=...)` keeps its exact behavior.
78
+ - If you have persistent state on disk (`~/.livepilot/taste.json`):
79
+ v1.13 migrates `novelty_band` (flat float) to `novelty_bands` (dict)
80
+ on first read. Old clients reading the file still see the flat field.
81
+ - Tests added across 9 new files — no existing test needed editing
82
+ beyond `test_experiment_engine.py` (which gains PR3 coverage but
83
+ keeps every pre-PR3 test passing).
84
+
85
+ ## 1.12.2 — Post-release audit reliability fixes (April 18 2026)
86
+
87
+ Six issues surfaced by an immediate post-v1.12.0 deep audit (parallel
88
+ code-reviewer subagents + manual verification). All fixed TDD-style —
89
+ every bug now has a named regression guard in the test suite.
90
+
91
+ **No tool count change** (still 398). **+11 regression tests**
92
+ (2195 → 2206 passing, 1 skipped, 0 failed).
93
+
94
+ ### Critical fixes (reliability in hot paths)
95
+
96
+ - **`send_capture` no longer blocks `send_command`** (BUG-audit-C1).
97
+ The M4L bridge shared `_cmd_lock` between `send_capture` and
98
+ `send_command`, so any concurrent MCP tool invocation during a
99
+ recording was blocked for the full capture duration (up to 35s).
100
+ The two operations use independent receiver state
101
+ (`_capture_future` vs `_response_callback`) and now use
102
+ independent locks (`_capture_lock` + `_cmd_lock`).
103
+ [`mcp_server/m4l_bridge.py:780-790, 912-913`](mcp_server/m4l_bridge.py).
104
+ - **`_parse_osc` no longer crashes on malformed packets**
105
+ (BUG-audit-C2). `data.index(b'\x00')` raised `ValueError` when a
106
+ packet had no null byte — on UDP port 9880 collision with
107
+ non-OSC traffic, every incoming packet logged a noisy stack
108
+ trace. Replaced with `data.find(...)` + bounds checks on every
109
+ offset; malformed packets drop silently.
110
+ [`mcp_server/m4l_bridge.py:513-565`](mcp_server/m4l_bridge.py).
111
+ - **`classify_simpler_slices` returns structured error on bad WAV**
112
+ (BUG-audit-C3). `sf.read()` was unguarded — corrupt or missing
113
+ files raised `soundfile.LibsndfileError` through the MCP
114
+ framework as an internal server error. Every other tool in the
115
+ module returns `{"error": ...}` dicts. Now wrapped in
116
+ `try/except` for consistent error shape.
117
+ [`mcp_server/tools/analyzer.py:571-581`](mcp_server/tools/analyzer.py).
118
+
119
+ ### High-severity fixes (API consistency)
120
+
121
+ - **`batch_set_parameters` rejects negative `parameter_index`**
122
+ (BUG-audit-H3). `set_device_parameter` validates this at the MCP
123
+ layer; `batch_set_parameters` didn't, leaking an unstructured
124
+ `IndexError` from the Remote Script. Now rejected with a clear
125
+ ValueError at normalisation time.
126
+ [`mcp_server/tools/devices.py:318-328`](mcp_server/tools/devices.py).
127
+
128
+ ### Medium-severity fixes
129
+
130
+ - **`_enrich_slice_response` uses positional fallback for missing
131
+ `index` field** (BUG-audit-M2). Direct `s["index"]` access in a
132
+ list comprehension raised `KeyError` on bridge version skew.
133
+ Now uses `s.get("index", i)` with `enumerate` fallback.
134
+ [`mcp_server/tools/analyzer.py:57-62`](mcp_server/tools/analyzer.py).
135
+ - **`test_identify_returns_none_for_free_port` is no longer flaky**
136
+ (BUG-audit-M4). The test hardcoded port 59999 as "almost
137
+ certainly free"; when another process on the machine held it
138
+ (hitting Claude Desktop during the audit), the test failed
139
+ without diagnosing a real code bug. Now uses
140
+ `socket.bind(("127.0.0.1", 0))` to get a kernel-assigned free
141
+ port, releases it, then verifies.
142
+ [`tests/test_startup_safety.py:50-70`](tests/test_startup_safety.py).
143
+
144
+ ### .amxd binary patched in place
145
+
146
+ - `m4l_device/LivePilot_Analyzer.amxd` had the `ping` response
147
+ version string patched from `"1.12.0"` → `"1.12.2"` via direct
148
+ byte replacement (same-length delta, size preserved). No Max
149
+ re-export needed.
150
+ - `m4l_device/livepilot_bridge.js` source version also updated for
151
+ the next full rebuild.
152
+
153
+ ---
154
+
155
+ ## 1.12.1 — Silent-failure fixes + slice classifier (April 18 2026)
156
+
157
+ Reconciles the "separate git stash" called out under v1.12.0's Known
158
+ limitations — the 2026-04-18 Villalobos-groove session surfaced four
159
+ silent-failure bugs and the need for a drum-slice spectral classifier.
160
+
161
+ **+1 tool (397 → 398): `classify_simpler_slices`.** +43 regression
162
+ guards (pure-Python, run without a live Ableton).
163
+
164
+ ### Ship-stoppers fixed
165
+
166
+ - **`get_master_rms.pitch.midi_note` clamped** (BUG-F1) — polyphonic
167
+ pitch detector emitted values up to 319.15 with amplitude 0. Now
168
+ drops readings with zero amplitude or out-of-range MIDI.
169
+ [`mcp_server/tools/analyzer.py:128-147`](mcp_server/tools/analyzer.py).
170
+ - **`get_simpler_slices` discloses base MIDI pitch** (BUG-F2) — Simpler
171
+ Slice mode uses C1 (MIDI 36) as slice 0, NOT C3. Response now
172
+ includes `base_midi_pitch` at top level and `midi_pitch` per slice.
173
+ Prevents the class of silent-audio bugs where MIDI notes at pitch
174
+ 60+ trigger nothing. Docstring updated to mandate using the
175
+ returned `midi_pitch`.
176
+ [`mcp_server/tools/analyzer.py:37-62, 462-487`](mcp_server/tools/analyzer.py).
177
+ - **`delete_track` last-track error message** (BUG-F3) — Ableton's
178
+ default rejection message was unrelated to the real cause ("you
179
+ can't add notes to a clip that doesn't exist yet"). Now pre-checks
180
+ `track_count` and raises a clear ValueError.
181
+ [`mcp_server/tools/tracks.py:93-112`](mcp_server/tools/tracks.py).
182
+ - **`batch_set_parameters` accepts aligned schema** (BUG-F4) — supports
183
+ `parameter_index` / `parameter_name` (matching `set_device_parameter`)
184
+ in addition to the legacy `name_or_index`. Rejects ambiguous entries
185
+ with clear errors.
186
+ [`mcp_server/tools/devices.py:292-328`](mcp_server/tools/devices.py).
187
+
188
+ ### New tool
189
+
190
+ - **`classify_simpler_slices(track, device, file_path?)`** — runs
191
+ FFT-based spectral analysis on a Simpler's slice boundaries, returns
192
+ each slice labeled as KICK / SNARE / HAT / ghost plus feature
193
+ breakdown (peak, rms, band %). Validated thresholds from the
194
+ 2026-04-18 Villalobos-groove session on "Break Ghosts 90 bpm":
195
+ - KICK: sub+low ≥ 45%, high < 40%
196
+ - HAT: high ≥ 70% AND mid < 25%
197
+ - SNARE: mid ≥ 25% AND high ≥ 40% AND peak ≥ 0.6
198
+ - ghost: peak < 0.35
199
+ Eliminates the "assume slice 0 = kick" class of bug.
200
+
201
+ ### New module
202
+
203
+ - **`mcp_server/sample_engine/slice_classifier.py`** — pure-Python
204
+ band-energy + peak classifier. Testable without Ableton
205
+ (`tests/test_slice_classifier.py` uses synthesized drum hits).
206
+ Exported `classify_segment()` and `classify_slices()` for direct
207
+ use outside MCP as well.
208
+
209
+ ### Documented bug entries
210
+
211
+ - `BUGS.md` gains a new **"F. 2026-04-18 Villalobos-groove creative
212
+ session"** section: F1-F4 fixed here, F5-F7 scoped to v1.13+, F8
213
+ wontfix (workaround documented).
214
+
215
+ ### Not included in this release
216
+
217
+ - `package.json` / `server.json` / plugin manifests / skill tool-count
218
+ sync — release-discipline is a separate task per CLAUDE.md's
219
+ "Version Bump" section. Run `python3 scripts/sync_metadata.py --fix`
220
+ before the next release.
221
+ - Registering `classify_simpler_slices` in
222
+ `tests/test_tools_contract.py::test_analyzer_tools_registered` — the
223
+ total-count assertion there already passes if regenerated; the
224
+ registration list is additive and can land with the metadata sync.
225
+
226
+ ---
227
+
228
+ ## 1.12.0 — Live 12 LOM completeness (April 18 2026)
229
+
230
+ Thirteen chunks closing the gap between LivePilot and Ableton Live 12.3.6's
231
+ Live Object Model. **325 → 397 tools (+72). 45 → 51 domains (+6).** Every
232
+ addition is hasattr-probed where the underlying API varies by Live version
233
+ — Core (12.0+), Enhanced (12.1.10+), and Full Intelligence (12.3+) tiers
234
+ keep their graceful degradation contract.
235
+
236
+ ### New tools by chunk
237
+
238
+ - **Chunk 1 — Song scale awareness (4 tools):** `get_song_scale`,
239
+ `set_song_scale`, `set_song_scale_mode`, `list_available_scales` — exposes
240
+ Live 12.0's Scale Mode at the song level. Remote Script probes
241
+ `song.scale_name` / `song.root_note`; missing on pre-12 falls back to
242
+ "Scale awareness unavailable".
243
+ - **Chunk 2 — Per-clip scale override (3 tools):** `get_clip_scale`,
244
+ `set_clip_scale`, `set_clip_scale_mode` — Live 12.0 MIDI clip-level override
245
+ for the song scale. Honors `clip.scale_name` and `clip.scale_mode`.
246
+ - **Chunk 3 — Tuning System (4 tools):** `get_tuning_system`,
247
+ `set_tuning_reference_pitch`, `set_tuning_note`, `reset_tuning_system` —
248
+ Live 12.1 microtonal tuning. Writes to `song.tuning_system`,
249
+ `tuning.reference_pitch`, and individual tuning-note cents.
250
+ - **Chunk 4 — Follow Actions (8 tools):** Clip-level Live 12.0 revamp
251
+ (multi-action enum, `follow_action_time`, `follow_action_enabled`) +
252
+ scene-level Live 12.2+ (`scene.follow_action`, `scene.follow_action_time`)
253
+ + preset wrapper for "A→B→C chain" common shapes.
254
+ - **Chunk 5 — Groove Pool (7 tools):** Pool enumeration, per-clip assignment,
255
+ master groove dial. Exposes Live 11+ `song.groove_pool` and the swing /
256
+ timing / random / velocity amount on each groove.
257
+ - **Chunk 6 — Take Lanes (6 tools):** Enumeration, creation, per-lane clip
258
+ creation. Live 12.0 read surface + 12.2 write surface — both paths handled
259
+ with `hasattr` probes so older hosts degrade cleanly.
260
+ - **Chunk 7 — Rack Variations + Macro CRUD (8 tools):** Variation
261
+ store/recall/delete + macro add/remove/randomize on Instrument/Audio-Effect
262
+ Racks (Live 11+).
263
+ - **Chunk 8 — Sample Slice CRUD (6 tools):** `insert_slice`, `move_slice`,
264
+ `remove_slice`, `clear_slices`, `reset_slices`, `import_slices_from_onsets`.
265
+ Writes to `SimplerDevice.sample.slices` (Live 11+).
266
+ - **Chunk 9 — Wavetable Modulation Matrix (5 tools):** Targets,
267
+ routing, amounts — completes the Wavetable surface alongside the existing
268
+ parameter tools (Live 11+).
269
+ - **Chunk 10 — Song/Track long-tail primitives (12 tools):** `tap_tempo`,
270
+ `nudge_tempo_down/up`, exclusive arm/solo, `capture_and_insert_scene`,
271
+ `count_in`, Ableton Link state, `jump_in_session_clip`, performance-impact
272
+ read, `appointed_device`.
273
+ - **Chunk 11 — Device A/B Compare (3 tools):** State read, toggle, copy
274
+ direction. Uses Live 12.3+ `Device.is_ab_state_enabled` / `ab_state`
275
+ where available; all three tools hasattr-probe so they return a clear
276
+ "unsupported on this Live build" error on 12.2 and older.
277
+ - **Chunk 12 — ControlSurface enumeration (2 tools):** `list_control_surfaces`,
278
+ `get_control_surface_info`. Always-available diagnostic for multi-surface
279
+ setups.
280
+ - **Chunk 13 — MIDI Tool bridge (4 tools):** `install_miditool_device`,
281
+ `set_miditool_target`, `get_miditool_context`, `list_miditool_generators`.
282
+ Exposes Live 12 MIDI Tools (Generators + Transformations) backed by
283
+ LivePilot generators (euclidean_rhythm, humanize, tintinnabuli). Ships
284
+ with both `.amxd` files pre-built from Live's factory templates — install
285
+ via `install_miditool_device()` which copies to the correct User Library
286
+ subfolders. **Note**: end-to-end Max-side integration is a known
287
+ follow-up; Max's `[js]` object may not locate `miditool_bridge.js` on
288
+ every machine without the folder being added to Max's File Preferences →
289
+ File Search Path. Server-side tools and config dispatch work standalone;
290
+ full round-trip notes-in-clip requires that Max path setup. Hence:
291
+ server shipped, Max-side user-setup step documented.
292
+
293
+ ### New domains (45 → 51)
294
+
295
+ Source of truth is module layout — six new files registered @mcp.tool()
296
+ decorators:
297
+
298
+ - `mcp_server/tools/scales.py` — serves both scales (Chunks 1–2) AND tuning
299
+ (Chunk 3) since both live on the Song object.
300
+ - `mcp_server/tools/follow_actions.py` — Chunk 4.
301
+ - `mcp_server/tools/grooves.py` — Chunk 5.
302
+ - `mcp_server/tools/take_lanes.py` — Chunk 6.
303
+ - `mcp_server/tools/diagnostics.py` — Chunk 12.
304
+ - `mcp_server/tools/miditool.py` — Chunk 13.
305
+
306
+ Chunks 7–11 extended existing domains (devices, clips) and did not introduce
307
+ new modules.
308
+
309
+ ### Known limitations
310
+
311
+ - **MIDI Tool bridge (Chunk 13) — Max-side file search**: the `.amxd` files
312
+ reference `js miditool_bridge.js` relatively. Max normally searches the
313
+ .amxd's folder first, but Live's MIDI Tool instantiation context can
314
+ bypass that. If `Max → Window → Max Console` shows "can't find file
315
+ miditool_bridge.js" when you fire the tool: open Max → Options → File
316
+ Preferences → add `~/Music/Ableton/User Library/MIDI Tools/Max Generators`
317
+ and `~/Music/Ableton/User Library/MIDI Tools/Max Transformations` to the
318
+ File Search Path, save, reload the device.
319
+ - A separate git stash ("pre-existing drift before LOM completeness work"
320
+ with `classify_simpler_slices` in flight) was left intact; the user will
321
+ reconcile it in its own release.
322
+
323
+ ### Not a breaking change
324
+
325
+ Every new tool is additive. No existing tool names, parameters, or return
326
+ shapes changed. Remote Script still boots cleanly on Live 12.0 — the 12.1+
327
+ and 12.3+ tools just return `STATE_ERROR` with a clear message when the host
328
+ lacks the underlying LOM attribute.
329
+
3
330
  ## 1.10.9 — Second-pass audit + deferred-bugs shipped (April 18 2026)
4
331
 
5
332
  Completes every non-feature item on the v1.10.8 audit backlog. 2116 → 2132
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  <p align="center">
19
19
  An agentic production system for Ableton Live 12.<br>
20
- 325 tools. 45 domains. Device atlas. Splice integration. Auto-composition. Spectral perception. Technique memory.
20
+ 398 tools. 52 domains. Device atlas. Splice integration. Auto-composition. Spectral perception. Technique memory.
21
21
  </p>
22
22
 
23
23
  <br>
@@ -79,8 +79,8 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
79
79
  │ └─────────────────┼──────────────────┘ │
80
80
  │ ▼ │
81
81
  │ ┌─────────────────┐ │
82
- │ │ 325 MCP Tools │ │
83
- │ │ 45 domains │ │
82
+ │ │ 398 MCP Tools │ │
83
+ │ │ 52 domains │ │
84
84
  │ └────────┬────────┘ │
85
85
  │ │ │
86
86
  │ Remote Script ──┤── TCP 9878 │
@@ -120,7 +120,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
120
120
 
121
121
  ## The Intelligence Layer
122
122
 
123
- 12 engines sit on top of the 325 tools. They give the AI musical judgment, not just musical execution.
123
+ 12 engines sit on top of the 398 tools. They give the AI musical judgment, not just musical execution.
124
124
 
125
125
  ### SongBrain — What the Song Is
126
126
 
@@ -172,7 +172,7 @@ Every engine follows: **measure before → act → measure after → compare**.
172
172
 
173
173
  ## Tools
174
174
 
175
- 325 tools across 45 domains. Highlights below — [full catalog here](docs/manual/tool-catalog.md).
175
+ 398 tools across 52 domains. Highlights below — [full catalog here](docs/manual/tool-catalog.md).
176
176
 
177
177
  <br>
178
178
 
@@ -360,7 +360,7 @@ The V2 intelligence layer. These tools analyze, diagnose, plan, evaluate, and le
360
360
  | Creative Constraints | 5 | constraint activation, reference-inspired variants |
361
361
  | Preview Studio | 5 | variant creation, preview rendering, comparison, commit |
362
362
 
363
- > **[View all 325 tools →](docs/manual/tool-catalog.md)**
363
+ > **[View all 398 tools →](docs/manual/tool-catalog.md)**
364
364
 
365
365
  <br>
366
366
 
@@ -587,7 +587,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for architecture details, code guidelines
587
587
 
588
588
  | Document | What's inside |
589
589
  |----------|---------------|
590
- | [Manual](docs/manual/index.md) | Complete reference: architecture, all 325 tools, workflows |
590
+ | [Manual](docs/manual/index.md) | Complete reference: architecture, all 398 tools, workflows |
591
591
  | [Intelligence Layer](docs/manual/intelligence.md) | How the 12 engines connect — conductor, moves, preview, evaluation |
592
592
  | [Device Atlas](docs/manual/device-atlas.md) | 1305 devices indexed — search, suggest, chain building |
593
593
  | [Samples & Slicing](docs/manual/samples.md) | 3-source search, fitness critics, slice workflows |
Binary file
@@ -95,7 +95,7 @@ function anything() {
95
95
  function dispatch(cmd, args) {
96
96
  switch(cmd) {
97
97
  case "ping":
98
- send_response({"ok": true, "version": "1.10.9"});
98
+ send_response({"ok": true, "version": "1.13.0"});
99
99
  break;
100
100
  case "get_params":
101
101
  cmd_get_params(args);
@@ -1,2 +1,2 @@
1
1
  """LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
2
- __version__ = "1.10.9"
2
+ __version__ = "1.13.0"
@@ -0,0 +1,32 @@
1
+ """Branch-native types — the shared substrate for Wonder, Preview Studio,
2
+ Experiment, and future producers (synthesis_brain, composer).
3
+
4
+ A BranchSeed is a producer-emitted creative intent (pre-compilation).
5
+ A CompiledBranch pairs a seed with a concrete plan ready for the execution
6
+ router. compiled_plan=None ⇒ analytical-only (directional suggestion).
7
+
8
+ This module is pure types + factory helpers. No I/O, no side effects, no
9
+ imports from other mcp_server subsystems.
10
+ """
11
+
12
+ from .types import (
13
+ BranchSeed,
14
+ CompiledBranch,
15
+ BranchSource,
16
+ RiskLabel,
17
+ NoveltyLabel,
18
+ seed_from_move_id,
19
+ freeform_seed,
20
+ analytical_seed,
21
+ )
22
+
23
+ __all__ = [
24
+ "BranchSeed",
25
+ "CompiledBranch",
26
+ "BranchSource",
27
+ "RiskLabel",
28
+ "NoveltyLabel",
29
+ "seed_from_move_id",
30
+ "freeform_seed",
31
+ "analytical_seed",
32
+ ]
@@ -0,0 +1,230 @@
1
+ """Branch-native types.
2
+
3
+ Design (see docs/specs/2026-03-17-livepilot-design.md and the branch-native
4
+ migration plan):
5
+
6
+ - Producers (Wonder, synthesis_brain, composer, technique memory) emit
7
+ BranchSeed objects expressing creative intent. A seed carries a hypothesis,
8
+ a source label, a distinctness reason, and novelty/risk labels — but no
9
+ executable plan yet.
10
+ - A compiler turns a seed into a CompiledBranch by attaching a plan. For
11
+ source="semantic_move" seeds, the existing semantic_moves.compiler is used.
12
+ For freeform/synthesis/composer seeds, the producer supplies the plan.
13
+ - CompiledBranch is the canonical post-compilation shape. PreviewVariant
14
+ and ExperimentBranch will migrate to thin wrappers over CompiledBranch
15
+ in later PRs; this PR only introduces the types.
16
+
17
+ compiled_plan=None means analytical_only — the branch is a directional
18
+ suggestion with no executable path. This case already exists in Wonder
19
+ (build_analytical_variant); the branch-native schema promotes it to a
20
+ first-class concept across the whole system.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import hashlib
26
+ from dataclasses import asdict, dataclass, field
27
+ from typing import Literal, Optional
28
+
29
+
30
+ BranchSource = Literal[
31
+ "semantic_move", # compiled via semantic_moves.compiler
32
+ "freeform", # producer supplies the compiled plan directly
33
+ "synthesis", # from synthesis_brain (PR9+)
34
+ "composer", # from composer branch-native path (PR11)
35
+ "technique", # from technique memory replay
36
+ ]
37
+ RiskLabel = Literal["low", "medium", "high"]
38
+ NoveltyLabel = Literal["safe", "strong", "unexpected"]
39
+
40
+
41
+ @dataclass
42
+ class BranchSeed:
43
+ """Pre-compilation creative intent.
44
+
45
+ Distinctness between branches is checked at seed layer — two seeds with
46
+ the same (source, hypothesis_hash, affected_scope_hash) are not distinct.
47
+
48
+ Fields:
49
+ seed_id: stable identifier. For semantic_move seeds, derived from move_id.
50
+ source: producer category.
51
+ move_id: populated when source="semantic_move"; empty otherwise.
52
+ hypothesis: one-line human-readable prediction of what the branch does.
53
+ protected_qualities: dimension names the producer promises not to regress.
54
+ affected_scope: {track_indices, device_paths, section_ids, clip_slots}.
55
+ distinctness_reason: why this seed is different from siblings in a set.
56
+ risk_label: execution safety tier.
57
+ novelty_label: creative novelty tier — maps to the safe/strong/unexpected UX triptych.
58
+ analytical_only: true ⇒ no plan will be compiled; branch is directional only.
59
+ """
60
+
61
+ seed_id: str
62
+ source: BranchSource
63
+ move_id: str = ""
64
+ hypothesis: str = ""
65
+ protected_qualities: list[str] = field(default_factory=list)
66
+ affected_scope: dict = field(default_factory=dict)
67
+ distinctness_reason: str = ""
68
+ risk_label: RiskLabel = "low"
69
+ novelty_label: NoveltyLabel = "strong"
70
+ analytical_only: bool = False
71
+
72
+ def to_dict(self) -> dict:
73
+ return asdict(self)
74
+
75
+
76
+ @dataclass
77
+ class CompiledBranch:
78
+ """Post-compilation branch — supersedes the move_id-locked ExperimentBranch.
79
+
80
+ Fields:
81
+ branch_id: stable identifier scoped to a branch set.
82
+ seed: the originating BranchSeed (carries source, hypothesis, move_id).
83
+ compiled_plan: execution-router-ready plan dict, or None for analytical-only.
84
+ execution_log: per-step results after run/commit; [{tool, backend, ok, error, result}].
85
+ before_snapshot / after_snapshot: captured session state dicts.
86
+ evaluation: evaluator result dict; shape determined by the evaluator.
87
+ score: composite quality score (0-1).
88
+ status: pending | running | evaluated | committed | discarded
89
+ | interesting_but_failed ← PR7 will gate on this
90
+ created_at_ms / executed_at_ms: timestamps.
91
+ """
92
+
93
+ branch_id: str
94
+ seed: BranchSeed
95
+ compiled_plan: Optional[dict] = None
96
+ execution_log: list = field(default_factory=list)
97
+ before_snapshot: Optional[dict] = None
98
+ after_snapshot: Optional[dict] = None
99
+ evaluation: Optional[dict] = None
100
+ score: float = 0.0
101
+ status: str = "pending"
102
+ created_at_ms: int = 0
103
+ executed_at_ms: int = 0
104
+
105
+ @property
106
+ def move_id(self) -> str:
107
+ """Back-compat convenience — delegates to seed.move_id.
108
+
109
+ Lets callers that currently read branch.move_id keep working once
110
+ ExperimentBranch migrates to wrap CompiledBranch.
111
+ """
112
+ return self.seed.move_id
113
+
114
+ @property
115
+ def analytical_only(self) -> bool:
116
+ """A branch is analytical when the seed says so OR when no plan exists."""
117
+ return self.seed.analytical_only or self.compiled_plan is None
118
+
119
+ def to_dict(self) -> dict:
120
+ d = {
121
+ "branch_id": self.branch_id,
122
+ "seed": self.seed.to_dict(),
123
+ "move_id": self.move_id,
124
+ "score": self.score,
125
+ "status": self.status,
126
+ "analytical_only": self.analytical_only,
127
+ "created_at_ms": self.created_at_ms,
128
+ }
129
+ if self.compiled_plan:
130
+ d["step_count"] = self.compiled_plan.get("step_count", 0)
131
+ d["summary"] = self.compiled_plan.get("summary", "")
132
+ if self.before_snapshot is not None:
133
+ d["before_snapshot"] = self.before_snapshot
134
+ if self.after_snapshot is not None:
135
+ d["after_snapshot"] = self.after_snapshot
136
+ if self.evaluation is not None:
137
+ d["evaluation"] = self.evaluation
138
+ if self.execution_log:
139
+ d["execution_log"] = self.execution_log
140
+ d["steps_ok"] = sum(1 for e in self.execution_log if e.get("ok"))
141
+ d["steps_failed"] = sum(1 for e in self.execution_log if not e.get("ok"))
142
+ return d
143
+
144
+
145
+ # ── Factory helpers ──────────────────────────────────────────────────────
146
+
147
+ def _stable_seed_id(prefix: str, *parts: str) -> str:
148
+ """Deterministic seed_id from parts — no timestamps, stable across runs."""
149
+ seed = "|".join(str(p) for p in parts)
150
+ return f"{prefix}_" + hashlib.sha256(seed.encode()).hexdigest()[:10]
151
+
152
+
153
+ def seed_from_move_id(
154
+ move_id: str,
155
+ seed_id: str = "",
156
+ hypothesis: str = "",
157
+ novelty_label: NoveltyLabel = "strong",
158
+ risk_label: RiskLabel = "low",
159
+ protected_qualities: Optional[list[str]] = None,
160
+ distinctness_reason: str = "",
161
+ ) -> BranchSeed:
162
+ """Build a semantic_move seed — the baseline producer path.
163
+
164
+ Mirrors how wonder_mode.engine.discover_moves already hands moves to
165
+ build_variant. In later PRs, the Wonder distinctness selector will emit
166
+ BranchSeed directly instead of move dicts.
167
+ """
168
+ if not seed_id:
169
+ seed_id = _stable_seed_id("seed", "move", move_id, novelty_label)
170
+ return BranchSeed(
171
+ seed_id=seed_id,
172
+ source="semantic_move",
173
+ move_id=move_id,
174
+ hypothesis=hypothesis or f"Apply {move_id}",
175
+ novelty_label=novelty_label,
176
+ risk_label=risk_label,
177
+ protected_qualities=protected_qualities or [],
178
+ distinctness_reason=distinctness_reason,
179
+ )
180
+
181
+
182
+ def freeform_seed(
183
+ seed_id: str,
184
+ hypothesis: str,
185
+ affected_scope: Optional[dict] = None,
186
+ protected_qualities: Optional[list[str]] = None,
187
+ distinctness_reason: str = "",
188
+ novelty_label: NoveltyLabel = "strong",
189
+ risk_label: RiskLabel = "medium",
190
+ source: BranchSource = "freeform",
191
+ ) -> BranchSeed:
192
+ """Build a freeform seed — producer has a concrete hypothesis without a move.
193
+
194
+ The compiled plan is attached downstream by the producer; this seed
195
+ carries intent only. Used by synthesis_brain, composer, and any
196
+ producer that doesn't go through semantic_moves.compiler.
197
+ """
198
+ return BranchSeed(
199
+ seed_id=seed_id,
200
+ source=source,
201
+ hypothesis=hypothesis,
202
+ affected_scope=affected_scope or {},
203
+ protected_qualities=protected_qualities or [],
204
+ distinctness_reason=distinctness_reason,
205
+ novelty_label=novelty_label,
206
+ risk_label=risk_label,
207
+ )
208
+
209
+
210
+ def analytical_seed(
211
+ seed_id: str,
212
+ hypothesis: str,
213
+ source: BranchSource = "freeform",
214
+ protected_qualities: Optional[list[str]] = None,
215
+ ) -> BranchSeed:
216
+ """Build an analytical-only seed — no plan will be compiled.
217
+
218
+ Used when a producer has a directional suggestion but no executable path:
219
+ - Wonder fallback when no move matches (already present as
220
+ build_analytical_variant in wonder_mode.engine).
221
+ - Synthesis brain on opaque devices where parameter state can be read
222
+ but safe mutations cannot be proposed yet.
223
+ """
224
+ return BranchSeed(
225
+ seed_id=seed_id,
226
+ source=source,
227
+ hypothesis=hypothesis,
228
+ protected_qualities=protected_qualities or [],
229
+ analytical_only=True,
230
+ )
@@ -1 +1,10 @@
1
- """Composer Engine — auto-composition from text prompts via Splice + Sample Engine."""
1
+ """Composer Engine — auto-composition from text prompts via Splice + Sample Engine.
2
+
3
+ PR11 adds branch_producer.propose_composer_branches() for emitting
4
+ multiple section-hypothesis BranchSeeds alongside the existing
5
+ single-plan compose() entry point.
6
+ """
7
+
8
+ from .branch_producer import propose_composer_branches
9
+
10
+ __all__ = ["propose_composer_branches"]