livepilot 1.23.2 → 1.23.4
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.
- package/CHANGELOG.md +124 -0
- package/README.md +108 -10
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +39 -1
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/cross_pack_chain.py +658 -0
- package/mcp_server/atlas/demo_story.py +700 -0
- package/mcp_server/atlas/extract_chain.py +786 -0
- package/mcp_server/atlas/macro_fingerprint.py +554 -0
- package/mcp_server/atlas/overlays.py +95 -3
- package/mcp_server/atlas/pack_aware_compose.py +1255 -0
- package/mcp_server/atlas/preset_resolver.py +238 -0
- package/mcp_server/atlas/tools.py +1001 -31
- package/mcp_server/atlas/transplant.py +1177 -0
- package/mcp_server/mix_engine/state_builder.py +44 -1
- package/mcp_server/runtime/capability_state.py +34 -3
- package/mcp_server/runtime/remote_commands.py +10 -0
- package/mcp_server/server.py +45 -24
- package/mcp_server/tools/agent_os.py +33 -9
- package/mcp_server/tools/analyzer.py +84 -23
- package/mcp_server/tools/browser.py +20 -1
- package/mcp_server/tools/devices.py +78 -11
- package/mcp_server/tools/perception.py +5 -1
- package/mcp_server/tools/tracks.py +39 -2
- package/mcp_server/user_corpus/__init__.py +48 -0
- package/mcp_server/user_corpus/manifest.py +142 -0
- package/mcp_server/user_corpus/plugin_engine/__init__.py +39 -0
- package/mcp_server/user_corpus/plugin_engine/detector.py +579 -0
- package/mcp_server/user_corpus/plugin_engine/manual.py +347 -0
- package/mcp_server/user_corpus/plugin_engine/research.py +247 -0
- package/mcp_server/user_corpus/runner.py +261 -0
- package/mcp_server/user_corpus/scanner.py +115 -0
- package/mcp_server/user_corpus/scanners/__init__.py +18 -0
- package/mcp_server/user_corpus/scanners/adg.py +79 -0
- package/mcp_server/user_corpus/scanners/als.py +144 -0
- package/mcp_server/user_corpus/scanners/amxd.py +374 -0
- package/mcp_server/user_corpus/scanners/plugin_preset.py +202 -0
- package/mcp_server/user_corpus/tools.py +904 -0
- package/mcp_server/user_corpus/wizard.py +224 -0
- package/package.json +2 -2
- package/remote_script/LivePilot/__init__.py +1 -1
- package/remote_script/LivePilot/browser.py +7 -2
- package/remote_script/LivePilot/devices.py +9 -0
- package/remote_script/LivePilot/simpler_sample.py +98 -0
- package/requirements.txt +3 -3
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,129 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.23.4 — 2026-04-30
|
|
4
|
+
|
|
5
|
+
### Fixed (2026-04-30 live-test wave — 38 bugs surfaced, 36 fixed, 2 deferred to v1.23.5)
|
|
6
|
+
- **`als_deep_parse.py` — recursive `iter()` was returning nested rack defaults instead of authored macro values**, so every demo sidecar shipped with all macros at `0`. The fix replaces `device_elem.iter("MacroControls.N")` with a direct-child scan that only reads the rack's own macro controls. Live-verified against `Pioneer Drone` in `drone-lab__earth.als`: macro 1 "Rift Rate" = 1, macro 8 "Volume" = 95.25 (both were 0 before). All 104 demos re-parsed; macro values now match the producer's authored .als state. **This was the highest-impact bug in the wave** — every downstream tool (extract_chain, transplant, demo_story, pack_aware_compose, cross_pack_chain) consumes these macro values, so until this was fixed all phase tools operated on corrupted source data. (BUG-PARSER#1)
|
|
7
|
+
- **`als_deep_parse.py` — scale extraction always returned C Major** because `iter("ScaleInformation")` hit per-clip ScaleInformation elements (which default to C Major) before reaching the project-level LiveSet ScaleInformation. Fixed by using `root.find("LiveSet").find("ScaleInformation")` direct path. Added Live-9/10 fallback for `<Root>` vs `<RootNote>`. Voice Box demo 04 now correctly reports F Minor. (BUG-E4)
|
|
8
|
+
- **`atlas_demo_story` crashed with `TypeError: tuple | set` on any demo containing GroupTracks** (every Drone Lab and Mood Reel demo). One-character fix: `(_AUDIO_EFFECT_GROUP,) | _FX_BUS_CLASSES` → `{_AUDIO_EFFECT_GROUP} | _FX_BUS_CLASSES`. (BUG-E1#1)
|
|
9
|
+
- **`atlas_extract_chain` emitted generic `"Macro N"` parameter names** instead of producer-assigned labels. Live calls to `set_device_parameter(parameter_name="Macro 2")` would silently NOT-FOUND when the rack actually had a name like "Crunch" or "Rift Rate" at that index. Now resolves the matching preset sidecar via the new `mcp_server/atlas/preset_resolver.py` helper and emits the real producer name (e.g. `parameter_name: "Rift Rate"`), with `parameter_index` as a fallback addressing field. Source tag `[SOURCE: als-parse+adg-parse]` when the name was successfully resolved. (BUG-E2#1)
|
|
10
|
+
- **`atlas_extract_chain.load_browser_item` steps were missing `uri` and `track_index`** — non-executable as-emitted. Now embeds a `browser_search_hint: {name_filter, suggested_path}` that the agent passes to `search_browser` to resolve the FileId-keyed runtime URI before calling `load_browser_item`. Same pattern applied to `atlas_pack_aware_compose`. The new shared `preset_resolver` module also provides `emit_load_step()` for any future caller. (BUG-E2#4 + BUG-F1#2)
|
|
11
|
+
- **`atlas_pack_aware_compose` `transpose_semitones` aesthetic override was a silent no-op** — `for step in steps: step = dict(step); ...` mutated a copy that was never written back. Fixed in [cross_pack_chain.py](mcp_server/atlas/cross_pack_chain.py) (the actual locus despite the bug-id naming). Now `for i, step in enumerate(steps): ... ; steps[i] = step`. (BUG-F2#3)
|
|
12
|
+
- **`atlas_extract_chain` emitted `create_audio_track` for `GroupTrack` and `ReturnTrack` source types**, breaking routing topology when the plan was executed. Now emits `create_return_track` for ReturnTrack and `manual_step` (with clear instructions) for GroupTrack since LivePilot has no `create_group_track` tool. (BUG-E2#3 + #7)
|
|
13
|
+
- **`atlas_extract_chain` `parameter_fidelity="approximate"` sorted by `abs(value)` instead of deviation-from-default** — pinned-max macros (127) ranked above intentionally-tweaked mid-range macros (50). Now cross-references the matching preset sidecar's factory default values and sorts by `abs(demo_value - preset_default)`. Falls back to `abs(value)` when no sidecar match. (BUG-E2#5)
|
|
14
|
+
- **`atlas_extract_chain` listed `PluginDevice` in `_NATIVE_INSTRUMENT_CLASSES`** — would have emitted non-executable `insert_device(device_class="PluginDevice")` for any third-party VST/AU. Now routes PluginDevice to `manual_rebuild` action with vendor-name lookup instructions. (BUG-E2#PluginDevice)
|
|
15
|
+
- **`atlas_extract_chain` fuzzy track-name match silently picked the first hit** when multiple tracks contained the substring (e.g. `track_name="plane"` against `drone-lab__emergent-planes` which has 6 tracks containing "Plane"). Now emits `matched_track` echo + `ambiguity_warning` listing the other candidates. (BUG-extract_chain-fuzzy)
|
|
16
|
+
- **`atlas_macro_fingerprint` synonym dict failed on producer-stylized Unicode macro names**. Drone Lab presets use names like `"Nøize Ω"`, `"MØD Rate"`, `"Fil†er Amount"`, `"BLASTS ++"` — the dict had bland canonicals (`"volume"`, `"attack"`, `"tone"`) and never matched. Same-pack same-class lookup returned 0 matches despite 37 candidate sibling presets. Added `_ascii_fold()` with explicit Unicode glyph substitutions (ø→o, †→t, Ω→empty) before NFKD decomposition. Live-verified: same canonical repro now returns 4 matches (was 0); `MØD Rate` correctly canonicalizes to `lfo_rate`. (BUG-D#2)
|
|
17
|
+
- **`atlas_macro_fingerprint.matching_macros` truncated to 1-2 items** even when many macros overlapped, defeating score auditing. Now caps at 5 with a `total_matching_macros: int` count field so callers know the full overlap. (BUG-D#3)
|
|
18
|
+
- **`atlas_macro_fingerprint` docstring promised live-source path that raises `NotImplementedError`**. Updated to disclose that as of v1.23.4 only the corpus-source path is implemented; live-source is stubbed and returns an actionable error. (BUG-D#1)
|
|
19
|
+
- **`atlas_transplant` REMAP `executable_steps` used naive global transpose**, not pitch-class-set transformation. The `_remap_pitch_class` function existed and computed correct per-note offsets but was only used in human-readable detail strings. Demo sidecars don't expose clip note data so per-note `modify_notes` (Option A) wasn't viable. Switched to Option B: emit `set_song_scale` step paired with the existing reasoning artifact, leveraging Live's scale-snap for scale-locked clips. Documented the limitation for non-snap clips. (BUG-C#1)
|
|
20
|
+
- **`atlas_transplant` Phase-D macro-fingerprint suggestions carried wrong `decision` verb** (REMAP instead of REPLACE) — agents iterating the plan and matching `decision == "REMAP"` would conflate scale-degree transforms with preset-swap suggestions. Changed to REPLACE. (BUG-C#3)
|
|
21
|
+
- **`atlas_transplant` accepted invalid `source_namespace` and silently fell through** to a minimal-fallback struct with a generic warning. Added explicit allow-list guard at function entry — returns `{"error": "Unknown source_namespace: '...'", "status": "error"}`. (BUG-C#4)
|
|
22
|
+
- **`atlas_transplant` output `source.entity_id` echoed input form instead of canonical resolved slug** (`drone_lab__earth` stayed underscored even after the lookup resolved against the hyphenated sidecar). Now resolves to canonical hyphen form. (BUG-C#5)
|
|
23
|
+
- **`atlas_transplant._detect_producer_anchor` returned only the first match** in `_PRODUCER_ANCHORS`, so `target_aesthetic="arca metallic"` on a `drone-lab` source silently lost the Arca anchor. Now checks target_aesthetic keywords first (more relevant), then source entity_id, deduplicates, and joins both anchors into the reasoning artifact. (BUG-C#6)
|
|
24
|
+
- **`atlas_pack_aware_compose` Henke/Monolake artist alias mapped to wrong slug** because `_parse_artist_section` slugified `"Robert Henke (Monolake)"` to `"robert_henke_monolake"` while `_ARTIST_ALIASES` pointed `"henke"` and `"monolake"` to `"robert_henke"`. The vocabulary lookup returned empty → pack_anchors never loaded → cohort dilution. Fixed by stripping parenthetical aliases in `_parse_artist_section` before slugifying. Same fix automatically resolves Aphex Twin, OPN, Plastikman, Com Truise, and any other artist with parenthetical alternates. Verified: dub-techno-spectral-drone-bed brief now correctly produces a `[pitchloop89, convolution-reverb, drone-lab]` cohort. (BUG-F1#1)
|
|
25
|
+
- **`atlas_pack_aware_compose` `track_count` silently capped at 12** with no signal that the response was truncated. Extended `_DEFAULT_ROLE_MIX` from 12 to 20 entries, added `requested_vs_returned: {requested, returned, max_supported}` field when truncation happens. (BUG-F1#3)
|
|
26
|
+
- **`atlas_pack_aware_compose` had ~30 latent vocabulary gaps** for cross-workflow themes (footwork, breakcore, juke, jungle, orchestral, etc.) and 9 broken genre aliases pointing to nonexistent vocab keys (`"ambient"` → `"ambient"` when the vocab key was `"ambient_drone"`). Footwork/breakcore briefs no longer fall through to a generic ambient cohort. (BUG-F1#4 + 9 latent broken aliases)
|
|
27
|
+
- **`atlas_pack_aware_compose` eclectic mode for Mica Levi briefs returned `"industrial pastoral"` boilerplate** because Mica Levi was missing from `_ARTIST_ALIASES`, orchestral packs were missing from `_PACK_AESTHETIC_AXES`, and `tension_resolution` was a static template that didn't interpolate the actual cohort. Added Mica Levi + Bibio + Caterina Barbieri + Henderson + Iftah + Reich + Reznor/Ross aliases; added orchestral pack axes; rewrote tension_resolution to interpolate the real cohort. (BUG-F1#5)
|
|
28
|
+
- **`atlas_pack_aware_compose` preset deduplication broke under small cohorts** — 4 of 6 tracks could end up with the same preset because `_select_preset_for_role` early-exited on "strong" fingerprint, ignoring the caller's `used_presets` exclusion intent. Now threads `used_presets` into the function and skips already-used during scoring. Verified: a representative `decayed-pad` brief now produces 6 unique presets across 6 tracks. (BUG-F1#6)
|
|
29
|
+
- **`atlas_pack_aware_compose` wrote `tension_resolution` to BOTH `track_proposal[0]` AND `reasoning_artifact`** (double-write). Removed the track-level write; the reasoning artifact is the source of truth. (BUG-F1#7)
|
|
30
|
+
- **`atlas_cross_pack_chain` numeric value extractor matched digits inside device names** — text "PitchLoop89 with Pitch A +0.05 cents" returned `89` instead of `0.05`. Added negative lookbehind `(?<![A-Za-z\d])` to the regex. (BUG-F2#1)
|
|
31
|
+
- **`atlas_cross_pack_chain` mid-line `→` inside parentheses shattered one step into 3 garbage steps** — Henke workflow text "(voice A → R, voice B → L)" caused the splitter to emit three truncated lines. Replaced bare `re.split` with paren-aware splitter that masks `(...)` blocks before detecting split positions. (BUG-F2#2)
|
|
32
|
+
- **`atlas_cross_pack_chain` verb pattern `"chain "` false-positively matched `"Sidechain"` and `"master-bus chain"`** — text like "Sidechain Compressor on the 808" wrongly classified as `set_track_send`. Tightened to `"chain to "` / `"chain into "`. (BUG-F2#5)
|
|
33
|
+
- **`atlas_cross_pack_chain` numbered-continuation lines retained stale step number in `raw_text`** — output step renumbered as 3 still had `raw_text` starting with `"2. → ..."`. Now appends number-stripped `content` instead of original `line`. (BUG-F2#6)
|
|
34
|
+
- **`atlas_cross_pack_chain.workflow_meta` did not propagate `devices_used`** from the YAML — callers had to re-query the atlas to know what devices a workflow needed. Added the field. (BUG-F2#7)
|
|
35
|
+
- **`atlas_cross_pack_chain` pack-prefixed load lines mis-classified as `manual_step`** — text like `"Inspired by Nature \`tree_tone\` on a sustained Cmaj7 chord"` (pack name shadowing the device-name match) failed `startswith` check on `_KNOWN_DEVICE_FRAGMENTS`. Extended classifier to substring-search the device fragment in the first 80 chars after the prefix, with `_` → space normalization so `tree_tone` matches the `tree tone` fragment. (BUG-F2#4)
|
|
36
|
+
- **`atlas_demo_story` `focus_tracks` filter was exact-match only** — `focus_tracks=["drum","kit"]` against track named `"4-Ship Noise Kit"` returned empty. Now uses fuzzy substring match: `not any(tok.lower() in t_name.lower() for tok in focus_tracks)`. (BUG-E2-focus)
|
|
37
|
+
- **`atlas_demo_story` terse mode stripped the producer-vocabulary anchor** — the terse branch never called `_detect_producer_anchor` even though pack identity is the most useful anchor in a 2-3 sentence summary. Now emits one-line anchor in terse output. (BUG-E3)
|
|
38
|
+
- **`atlas_demo_story` `production_decision` fell back to raw class name** when `user_name` was empty — `"'InstrumentGroupDevice' adds textural density."` Now falls back to track name when user_name is missing. (BUG-E5)
|
|
39
|
+
- **`atlas_demo_story` bad-ID error suggested a shell command** (`"use ls ~/.livepilot/..."`) instead of listing real demo IDs an LLM caller can actually use. Now enumerates `DEMO_PARSES_ROOT` and includes 10 real `available_demos` in the error response. (BUG-E6)
|
|
40
|
+
- **`ensure_analyzer_on_master` cold-start timeout** — first call after Live boot timed out at 15 s on a fresh empty session even when the analyzer was at the expected User Library path. Recorded as a known intermittent (workaround: retry; underlying browser-cache cold-start latency). Tracked but not fixed in v1.23.4. (BUG-T#1)
|
|
41
|
+
|
|
42
|
+
### Added (architectural — supports the Phase E/F fixes above)
|
|
43
|
+
- **`mcp_server/atlas/preset_resolver.py`** — new shared helper module that maps a demo track's device (class + user_name) to its matching preset sidecar. Returns `{found, match_type, sidecar_path, preset_name, macro_names: {idx: name}, browser_search_hint: {name_filter, suggested_path}, preset_file}`. Powers BUG-E2#1 (Macro N → real names) and BUG-E2#4 + BUG-F1#2 (load_browser_item URI hint). Exposes `resolve_preset_for_device()`, `lookup_macro_name()` convenience getter, and `emit_load_step()` for plan emitters. Tested at 12/12 with synthetic + real-corpus integration tests.
|
|
44
|
+
- **38 net-new tests** across the wave (12 preset_resolver + 19 extract_chain + 7 cross_pack_chain new test classes + supporting fixtures). Total suite: **3313 passing, 1 skipped, 0 failed** (up from 3180 in v1.23.3).
|
|
45
|
+
|
|
46
|
+
### Fixed (2026-04-30 round 5 — deep verification + 16 surfaced bugs)
|
|
47
|
+
After rounds 1-4 the suite was at 3323 tests passing. Round 5 dispatched 3 parallel sonnet agents for deep verification (corpus-wide crash sweep, cross-tool integration, edge cases + property invariants) — all 6 property invariants passed (`load_browser_item` shape, dry-run flag, scale source provenance, macro addressing, chain depth ≤4, REPLACE steps populated). The crash sweep covered **104 demos × 6 tools** with 0 failures. Integration + edge testing surfaced 16 NEW bugs that 4 fix agents resolved in parallel.
|
|
48
|
+
|
|
49
|
+
- **`atlas_transplant` PRESERVE `load_browser_item` steps were missing `browser_search_hint`** while `extract_chain` and `pack_aware_compose` had been emitting them since round 4 — inconsistent across tools, breaking the `search_browser → load_browser_item` execution pattern when an agent pulled a transplant plan. Fix routes through `preset_resolver.emit_load_step` with manual fallback. Verified: 6/6 PRESERVE steps on `drone-lab__earth` cinematic transplant now carry hint. (BUG-NEW#1)
|
|
50
|
+
- **`atlas_transplant` REPLACE decisions stripped the `detail` field** from `translation_plan` entries — agents iterating the plan to read `detail.remove_device` / `detail.add_device` always got `None`, even though `executable_steps` had the right delete/insert sequence. The internal decision dict carried `detail`, but the plan-builder only copied `element/decision/rationale/executable_steps`. Single-line fix added `"detail": dec.get("detail")` to the dict-builder. (BUG-INT#3)
|
|
51
|
+
- **Type-coercion family (5 bugs) — direct Python callers crashed on string-typed numeric params.** The MCP transport layer's `_coerce_schema_property` widens int/number params to also accept strings (Pydantic lax-mode coerces at the boundary), but direct callers bypass that. `atlas_macro_fingerprint(top_k="10")` raised `TypeError: slice indices must be integers`. `atlas_pack_aware_compose(track_count="5")` raised `TypeError: '<' not supported between 'int' and 'str'`. `atlas_pack_aware_compose(target_bpm="125.0")`, `atlas_transplant(target_bpm="130.0")`, and `atlas_cross_pack_chain(customize_aesthetic={"target_bpm": "bogus"})` all crashed similarly. Fix added `_coerce_int()` / `_coerce_float()` helpers in `pack_aware_compose.py` and try/except guards at every wrapper-level cast. Bogus strings now silently fall back to defaults instead of crashing. (BUG-EDGE#1, #2, #3, #4, #5)
|
|
52
|
+
- **`transplant()` accepted `target_scale_root=99` (out of pitch-class range) and stored it verbatim**, emitting an invalid `set_song_scale root=99` step. `tools.py` wrapper guard only rejected `< 0`, not `> 11`. Updated guard to `not (0 <= target_scale_root <= 11)` with explicit `-1` sentinel carve-out. Verified: `target_scale_root=99` returns a clear error, `target_scale_root=11` (B) still works. (BUG-EDGE#7)
|
|
53
|
+
- **`transplant()` inner function had no sentinel guard for `target_scale_root=-1`** — direct callers got a phantom REMAP decision and an invalid `set_song_scale root=-1` step. Fixed at function entry: normalize `< 0` to `None` to match the wrapper. (BUG-EDGE#6)
|
|
54
|
+
- **`atlas_cross_pack_chain` `load_browser_item` steps missed `browser_search_hint` when leading-noun lines defeated the device-name regex.** Lines like `"→ Echo with subtle wow/flutter"` and `"→ Reverb with cathedral IR"` were correctly classified as `load_browser_item` (because "echo" / "reverb" are in `_KNOWN_DEVICE_FRAGMENTS`) but `_extract_device_name()` returned None — no `device_name` → no hint. Fix adds a fallback scan of the first 80 chars against `_KNOWN_DEVICE_FRAGMENTS` after the regex misses. New `_FRAGMENT_TO_SUGGESTED_PATH` dict routes native FX fragments to `audio_effects` and synth fragments to `instruments` instead of the broad `sounds` default. Affected workflows: `boc-decayed-pad` (Echo, Reverb), `bibio-diy-bedroom-pop`, `henke-full-granular-chain`. (BUG-INT#1 / BUG-NEW#3)
|
|
55
|
+
- **`atlas_cross_pack_chain` `transpose_semitones` override silently no-op'd on 13/15 workflows** — the override loop only mutated existing `set_device_parameter` steps with parameter_name containing "pitch/note/transpose/tune", but most workflows parse as `manual_step` or `load_browser_item`. The transpose request was silently dropped. Fix appends a `manual_step` row signaling the transpose attempt when no existing steps are mutated. Verified: `boc_decayed_pad` with `transpose=-3` now emits 1 `manual_step`; `dub_techno_spectral_drone_bed` (which DOES have parseable Pitch A param) still mutates values without double-emit. (BUG-NEW#2)
|
|
56
|
+
- **Chain-recursion asymmetry — `atlas_extract_chain` and `atlas_demo_story` weren't walking into `dev.chains[]` even though `atlas_transplant` was** (added in round 2). On `mood-reel__chapter-one-by-thomas-ragsdale` track `3-Saturn Ascends`, `transplant` correctly surfaced Erosion (6 occurrences), but `extract_chain` reported only `[InstrumentGroupDevice, Delay, AudioEffectGroupDevice]` and `demo_story`'s narrative said the same — a producer asking "what's in this rack?" got 3 different answers from 3 tools. New `_collect_inner_chain_classes(dev, depth)` helper in extract_chain.py walks chains up to depth 4 and exposes them via a new `inner_chain_classes` field on each device + a compact `chain_summary` field on the rack's `load_browser_item` / `manual_rebuild` step (e.g. `"Nasal Bass → Pedal → Erosion → Limiter"`). `demo_story.py`'s `_build_chain_summary` was rewritten to recurse with bracket notation: `"InstrumentGroupDevice (Saturn Ascends) [InstrumentVector → Pedal → Erosion → Limiter]"`. Plan size unchanged (no nested execution steps). (BUG-INT#2)
|
|
57
|
+
- **`atlas_extract_chain` empty `track_name` silently picked the first track** because `"" in any_string` is always True in Python — pass-2 of `_find_track_by_name` matched every track. Added entry-point guard returning `{"error": "track_name is required and cannot be empty.", "available_tracks": [...]}`. (BUG-EDGE#8)
|
|
58
|
+
- **`atlas_pack_aware_compose` cap-at-20 truncation wasn't surfaced in `warnings`** — the `requested_vs_returned` field had it, but callers iterating the canonical `warnings` list missed the alert silently. Fix appends a human-readable warning when truncation happens. (BUG-EDGE#9)
|
|
59
|
+
- **`atlas_pack_aware_compose` `pack_cohort` was nested inside `brief_analysis`** but the docstring + CLAUDE.md described it as top-level — `r.get("pack_cohort")` returned None, breaking caller code that followed the docs. Added top-level alias while keeping `brief_analysis.pack_cohort` for backwards compatibility. (BUG-NEW#4)
|
|
60
|
+
|
|
61
|
+
### Fixed (2026-04-30 round 4 — startup warning + PluginDevice metadata)
|
|
62
|
+
- **Tool-count startup warning fired spuriously on direct tool-module imports.** Importing any tool module (e.g. `mcp_server.atlas.tools`) triggered `server.py` to run its self-test mid-import — at that moment, the importing module's own `@mcp.tool()` decorators hadn't yet fired (Python suspends the original import while server.py loads), so the registry probe under-counted by ~19 tools and the user saw `STARTUP SELF-TEST WARNING — _get_all_tools() returned 420 tools, expects 439` even on a healthy install. Fix: split `_assert_tool_registry_accessible()` into two phases. The "registry probe is at all accessible" guard (`actual > 0` — catches FastMCP internals breakage) stays at module load. The exact-count comparison (`actual == expected`) moved into a new `_assert_expected_tool_count()` called from `main()`, so all tool-module imports have completed regardless of which import path brought server.py in. The contract test (`tests/test_tools_contract.py::test_total_tool_count`) is unchanged and remains the authoritative drift gate. (BUG-T#2)
|
|
63
|
+
- **PluginDevice metadata extraction.** Third-party VST/AU/AAX plugins were previously surfaced as opaque `{class: "PluginDevice", user_name: "Serum"}` in sidecars, leaving `extract_chain`'s `manual_rebuild` step with nothing more than a class name to feed the agent. The .als XML format actually exposes plugin identity in plain XML (only the per-plugin parameter buffer is binary). New `_extract_plugin_metadata()` parses the `<PluginDesc>` block and pulls `{format, name, manufacturer, file_name, unique_id, exposed_param_count}` for VstPluginInfo / Vst3PluginInfo / AuPluginInfo / AaxPluginInfo variants. The factory-pack corpus contains zero PluginDevice instances (factory content can't depend on user-installed plugins), so 8 synthetic-XML fixture tests guard against rot. `extract_chain.py` was updated to surface the plugin field + emit a `browser_search_hint: {name_filter: "<plugin display name>", suggested_path: "plugins"}` so the agent can `search_browser` to find the plugin in Live's plugins/ folder. The note text now reads "'X' is a VST plugin by Valhalla DSP. Use search_browser..." instead of the previous generic placeholder. Param VALUES remain opaque per the .als format limitation — documented in the note. Old sidecars without the `plugin` field continue to work via the user_name fallback. (BUG-PARSER#5)
|
|
64
|
+
|
|
65
|
+
### Fixed (2026-04-30 round 3 — scale data enrichment)
|
|
66
|
+
- **Live 9/10 `.als` files left scale mode as a numeric index in 44 demo sidecars** (every Building Max Devices tutorial, plus a few cross-pack files). `scale.name` was a digit string like `"0"` or `"10"` instead of a mode name. Added `_LIVE_MODE_INDEX_TO_NAME` mapping (15 modes including the older Whole Tone / Diminished / Pentatonic / Harmonic Minor / Melodic Minor variants) and decode at the bottom of `get_scale()`. Verified: `building-max-devices__after-effects-export` now reports `Major` (was `"0"`); `final-result` reports `Minor Blues` (index 10); `arpeggiator` reports `Dorian` (index 2). Bonus discovery: `lost-and-found__lost-and-found-demo-set-01` now correctly surfaces `Harmonic Minor` (was masked as `"0"`). All 44 affected sidecars resolved. (BUG-PARSER#3)
|
|
67
|
+
- **Mood Reel construction-kit `.als` files store `C Major` at the LiveSet level** even when the producer-meaningful key is encoded in the filename (e.g. `Hope For The Future Fmin 130 bpm.als`). Ableton populated the per-clip ScaleInformation but left the project-level default. Added a filename-key fallback: when the .als-extracted scale is the C Major default AND the filename matches `\b([a-g][#b]?)(maj|min)\b`, the sidecar overrides with the filename-derived key and stamps `scale.source: "filename-fallback"`. When the .als has a non-default scale, it's trusted (`scale.source: "als-extract"`). Verified end-to-end via `atlas_demo_story` and `atlas_transplant`: Hope For The Future now reports `F Minor` (was C Major); Empty Streets reports `F# Minor`; Bright Side reports `G Major`. All 19 affected Mood Reel sidecars corrected. The 36 demos that genuinely have no key (tutorials, drone improvisations) keep `als-extract` C Major — fallback only fires when the filename actually encodes a key. (BUG-PARSER#4)
|
|
68
|
+
|
|
69
|
+
### Fixed (2026-04-30 round 2 — both deferred parser bugs)
|
|
70
|
+
- **`.adg` parser dropped 4 of 8 named macros on Pioneer Drone** (and similar ratios on other multi-rack presets). Root cause was richer than BUG-PARSER#1: the outer `InstrumentGroupDevice` literally stores generic `"Macro 4/5/6/8"` strings in its own `MacroDisplayNames` elements — the authentic names ("Movement", "Attack", "Release", "Volume") only exist on a nested `DrumGroupDevice`'s `MacroDisplayNames`. Ableton resolves the displayed name at runtime by following the macro binding encoded in each inner rack's `MacroControls.<i>/KeyMidi`: `Channel=16` signals an Ableton rack-macro mapping and `NoteOrController` holds the **outer rack macro index** the inner macro is bound to. The parser now scans nested branch presets for these `Channel=16` bindings and back-fills any "Macro N" slot on the outer rack with the inner rack's named `MacroDisplayNames.<i>`. Live-verified: Pioneer Drone now exposes all 8 names (Rift Rate, Crunch, Pitch, Movement, Attack, Release, Reverb, Volume); spot-checks on Shimmer & Sheen and Tubular Bells likewise resolve every named slot. All 3,813 .adg files re-parsed in 52.3 s. (BUG-PARSER#2)
|
|
71
|
+
- **Demo `.als` sidecars now expose nested rack-chain devices** — the `extract_device_summary` function previously returned a flat dict per device with no `chains` field, so REPLACE rules in `atlas_transplant` couldn't see Vinyl Distortion / Erosion / Redux when they lived inside racks (which is where producers actually put them). New schema (Schema A — nested): each rack device gains `"chains": [{"name": str, "devices": [<recursive>]}]`, with recursion capped at depth 4. The new `_extract_rack_chains()` helper follows `branch → DeviceChain → *DeviceChain → Devices` so it covers every Live chain variant (MidiToAudio, AudioToAudio, MidiToMidi) without hardcoded class names. All 104 .als files re-parsed in 13.0 s. Atlas-side `_extract_source_structure` in [transplant.py](mcp_server/atlas/transplant.py) was extended with `_walk_device_chain()` that recursively flattens the new schema into `device_inventory` — REPLACE rules now fire correctly. **42 demos in the corpus** now expose REPLACE-targetable devices (was 0 before this fix); end-to-end verification on `mood-reel__chapter-one-by-thomas-ragsdale` produces 2 REPLACE decisions (Vinyl Distortion + Erosion → Saturator/remove for `clean orchestral` target). (BUG-C#2)
|
|
72
|
+
- **End-to-end victory:** `atlas_extract_chain(demo_entity_id="drone-lab__earth", track_name="Pioneer Drone", parameter_fidelity="exact")` now produces an 11-step plan where ALL 8 macros carry producer-assigned names AND match the live Ableton ground truth values exactly: Rift Rate=1.0, Crunch=40.0, Pitch=77.0, Movement=10.0, Attack=115.0, Release=115.0, Reverb=64.0, Volume=95.25. Before this session: 2-step plan with no values and no URI. Before this round: 8 values but only 3 producer-assigned names.
|
|
73
|
+
|
|
74
|
+
### Added (User Corpus + Plugin Knowledge Engine — flagship feature)
|
|
75
|
+
- **User Corpus subsystem (`mcp_server/user_corpus/`)** — 14 new MCP tools that turn LivePilot's reasoning brain from "Ableton-shipped only" into "your actual library". The factory atlas knows 5264 devices across 33 Ableton packs; the user corpus indexes whatever else is on your machine — third-party VST3 / AU / AUv3 / VST2 / AAX / CLAP / LV2 plugins, your `.amxd` Max for Live devices, your `.adg` rack library, your sample folders. The result lives at `~/.livepilot/atlas-overlays/user/<entity_type>/<id>/identity.yaml` and is loaded by every reasoning tool (`atlas_search`, `atlas_chain_suggest`, `atlas_macro_fingerprint`, `atlas_describe_chain`) alongside the factory atlas, with each result tagged `source: factory_atlas | user_overlay:<namespace>` so the agent always knows whether a recommendation came from Ableton stock or your gear.
|
|
76
|
+
- **Plugin Knowledge Engine — 4-phase pipeline** (`mcp_server/user_corpus/plugin_engine/`):
|
|
77
|
+
- **Phase 1 — DETECT (`detector.py`)** — Walks platform plugin folders (`/Library/Audio/Plug-Ins/{VST3,Components}`, `~/Library/Audio/Plug-Ins/{VST3,Components}`, `~/Library/Application Support/Avid/Audio/Plug-Ins`, etc.) AND runs `auval -a` to enumerate AUv3 / Mac Catalyst plugins that don't live in standard Components folders. The auval path closed a silent ~66-plugin coverage gap on iOS-port-to-Mac plugins (Moog Animoog Z, Model 15, Cem Olcay's MIDI suite, Drambo, FieldScaper, AudioLayer, Audulus 4 — all previously invisible). Captures format, vendor, version, bundle ID, AU 4-char codes resolved via bundle reverse-DNS + copyright-string regex.
|
|
78
|
+
- **Phase 2 — CANONICALIZE (`tools.py::corpus_canonicalize_plugins`)** — Dedupes by `(canonical_vendor, normalized_name)` and prefers VST3 > AU > AAX/VST2/CLAP/LV2 as the primary format. Vendor canonicalization strips suffix variants ("Valhalla DSP, LLC" / "Valhalladsp" / "Valhalla DSP" all resolve to `valhalla`). Each canonical record carries `formats_available: [VST3, AU, AAX]` for reference but emits **exactly one** `format:<primary>` tag for indexing — eliminates the dual-indexing bug where a single plugin would show up twice in `format:au` AND `format:vst3` searches.
|
|
79
|
+
- **Phase 2.5 — CLUSTER (`tools.py::corpus_cluster_plugins`)** — Groups canonicalized plugins by vendor for batched research. Vendors with ≥2 plugins (Cem Olcay, ChowDSP, Valhalla, Moog, ElliottGarage) get one shared WebSearch + N synthesis runs; singletons get standalone treatment. Cuts per-plugin token cost by 3-5× on coherent product lines.
|
|
80
|
+
- **Phase 3 — RESEARCH (`tools.py::corpus_discover_manuals` + `corpus_research_targets`)** — Locates local manual files (PDFs, READMEs, plugin-bundle docs), then emits a structured WebSearch task packet the agent fulfills. The packet specifies queries, expected fields, and citation format so research output is consumable by Phase 4.
|
|
81
|
+
- **Phase 4 — SYNTHESIZE (`research.py` + `corpus_emit_synthesis_briefs`)** — Emits per-plugin briefs for sonnet-subagent dispatch. Each brief contains synthesis_inputs (manual + research_cache + preset_examples) and the synthesis_schema specifying every required field: `entity_id`, `entity_type: "installed_plugin"`, `name`, `description`, `tags` (with the **exactly-one-format** rule), `artists`, `sonic_fingerprint`, `reach_for`, `avoid`, `key_techniques`, `parameter_glossary`, `comparable_plugins`, `genre_affinity`, `producer_anchors`. The schema explicitly tells the agent what makes a producer-actionable identity vs a generic feature list.
|
|
82
|
+
- **Trim tool (`tools.py::corpus_trim_plugin_identity`)** — For utility plugins the user explicitly deprioritizes, slims an existing yaml to the overlay-required minimum (entity_id, entity_type, name, description, tags, artists). Used to keep search hits clean — a Pure Data wrapper or internet-radio AU stays indexed but doesn't bloat search context with its full schema.
|
|
83
|
+
- **Scanner ABC + 4 namespaces (`mcp_server/user_corpus/scanners/`)** — Pluggable scanner registry. Built-in scanners: `amxd` (Max for Live devices — patcher-JSON inspection for tag enrichment beyond filename keywords), `preset` (.adg / .aupreset / .vstpreset), `als` (project files), `audio` (sample folders), `plugin_inventory` (the Phase 1 detector wrapped as a scanner). Each scanner emits to its own namespace under `~/.livepilot/atlas-overlays/`: `user/`, `m4l-devices/`, `packs/`, `elektron/`. AppleDouble `._*` files explicitly excluded across all scanners (a real bug that bit 217 .amxd devices in the personal corpus dogfood).
|
|
84
|
+
- **Atlas overlay reasoning wiring (`mcp_server/atlas/overlays.py` + `tools.py`)** — `atlas_search`, `atlas_chain_suggest`, `atlas_macro_fingerprint`, and `atlas_describe_chain` now consult the user overlay alongside the bundled atlas with a 50/50 result-budget split. Each result carries `source` tagging so the agent knows the provenance. New `OverlayIndex` singleton with AND-token search semantics across all 4 namespaces (~800+ entries indexed end-to-end on a typical machine). Loader is idempotent and lazy — `load_overlays()` mutates the singleton in place, so reload is safe.
|
|
85
|
+
- **Tokenizer fix for hyphenated producer-vocabulary queries (`overlays.py::_tokenize`)** — Producer-style queries use natural-language phrasing ("Kraftwerk-style bass", "OTT-style multiband", "J Dilla SP-404 vibe") that the previous whitespace-only splitter rejected because hyphenated tokens never substring-matched indexed fields. Fixed: tokenize on whitespace + hyphens + apostrophes + slashes; drop stop-words (`style`, `vibe`, `tone`, `mood`, `era`, `school`, `like`, `kind`, `feel`, …); drop tokens shorter than 3 chars except domain-preserved short tokens (`fm`, `eq`, `808`, `303`, `dx`, etc.). End-to-end verification: "Kraftwerk-style bass" → `[kraftwerk, bass]` → `moog-model-d`; "OTT-style multiband" → `[ott, multiband]` → `brambos-woott`; "hysteresis tape" → `chow-chowtapemodel`.
|
|
86
|
+
- **`livepilot/skills/livepilot-corpus-builder/` skill** — Agent skill that drives the 4-phase pipeline interactively. Walks the user through path confirmation, scanner selection, AI-annotation opt-in. Documents the canonicalize → cluster → research → synthesize dispatch pattern, the Wave A vs singleton-batch routing, and the post-process trim step for deprioritized plugins.
|
|
87
|
+
- **`docs/USER_CORPUS_GUIDE.md` + `docs/PLUGIN_KNOWLEDGE_ENGINE.md`** — Full walk-through documentation. The corpus guide covers the user-facing pipeline (detect → canonicalize → cluster → research → synthesize) with example commands. The engine doc covers the architectural complement: how the engine indexes "what the plugins ARE" (sonic identity) vs the file-level corpus indexing "what's on disk" (file inventory).
|
|
88
|
+
- **Tool count: 439 → 453** (14 new `corpus_*` tools).
|
|
89
|
+
|
|
90
|
+
### Added (original v1.23.4 entries)
|
|
91
|
+
- **`atlas_pack_aware_compose` + `atlas_cross_pack_chain`** — Pack-Atlas Phase F. Two orchestration tools that wire the corpus into the LivePilot composer and execute multi-pack workflows. `atlas_pack_aware_compose` bootstraps a project with pack-coherent track selection from an aesthetic brief — parses artist/genre vocabularies, builds a pack cohort, selects real presets via macro-fingerprint similarity, and returns a full executable plan. Supports `pack_diversity="eclectic"` mode for deliberate aesthetic-conflict compositions with `tension_resolution` reasoning artifact. `atlas_cross_pack_chain` executes any of the 15 cross-pack workflow recipes step-by-step — parses signal_flow (numbered multi-line, list-of-strings, or list-of-dicts) into load_browser_item / insert_device / set_device_parameter / fire_clip / set_track_send actions; supports aesthetic overrides (`target_scale`, `target_bpm`, `transpose_semitones`); all execution is dry-run (result: "dry-run"). Both tools integrate Phases C+D+E: macro-fingerprint for preset selection, extract_chain step structure for executable plans, transplant aesthetic-replace logic for overrides. New files: `mcp_server/atlas/pack_aware_compose.py`, `mcp_server/atlas/cross_pack_chain.py`. Tool count: 437 → 439.
|
|
92
|
+
- **`atlas_demo_story` + `atlas_extract_chain`** — Pack-Atlas Phase E. Two complementary tools that turn the 104 demo .als sidecars into actionable artifacts. `atlas_demo_story` synthesizes a track-by-track narrative + production-sequence inference + suggested learning path from a demo sidecar. `atlas_extract_chain` surgically rebuilds a specific demo track's device chain as a dry-run execution plan (load_browser_item + insert_device + set_device_parameter steps), with three parameter-fidelity modes: exact, approximate, structure-only. Both tools read from local JSON sidecars — no Live connection required. New files: `mcp_server/atlas/demo_story.py`, `mcp_server/atlas/extract_chain.py`. Tool count: 435 → 437.
|
|
93
|
+
- **`atlas_transplant`** — Pack-Atlas Phase C. Source-to-target structural translation: adapts a demo project, preset chain, or workflow recipe from one musical context (BPM, scale, aesthetic) to another. Four decision types: PRESERVE (pitch intervals, macro ratios), SCALE (rhythmic density × BPM ratio with sanity clamp at ratio > 2.0), REMAP (scale-locked notes via pitch-class-set transformation, 7-mode table), REPLACE (aesthetic-incompatible devices — e.g. Vinyl Distortion → Saturator for cinematic target). Returns structured plan with executable `load_browser_item`, `set_device_parameter`, `set_clip_pitch`, `set_tempo` steps. Producer-vocabulary anchors in `reasoning_artifact` for known pack/aesthetic combinations. Integrates Phase D macro-fingerprint matcher for preset-source paths. New file: `mcp_server/atlas/transplant.py`. Performance: <0.4s p95. Tool count: 434 → 435.
|
|
94
|
+
- **`atlas_macro_fingerprint`** — Pack-Atlas Phase D. "More like this" search across all 3,813 preset sidecars by macro-fingerprint similarity. Source can be any corpus preset (pack slug + sidecar path). Scoring: 0.6 × macro-name-overlap-ratio (synonym-aware — 30-key synonym dict, top corpus vocabulary) + 0.4 × (1 − mean value distance). Returns top-K matches with per-match rationale prose and `[SOURCE: adg-parse]` citation. New file: `mcp_server/atlas/macro_fingerprint.py`. Performance: <0.3s p95 full corpus scan (3,813 sidecars, 33 packs). Live-device source path stubbed with `NotImplementedError` (`TODO: Phase D follow-up`). Tool count: 433 → 434.
|
|
95
|
+
|
|
96
|
+
## v1.23.3 — 2026-04-25
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
- **`classify_simpler_slices` now classifies slices when `file_path` is omitted (the v1.12 follow-up, finally closed).** The tool's docstring promotes "Always run this before programming drum patterns on a sliced break", but the file_path lookup had been a no-op since v1.11 — wrapped in `try/except` with the comment *"Bridge command may not exist yet"* and a fallback error message *"v1.12 follow-up"*. End-to-end verification against Ableton 12.4 + a Splice sliced break ("ff_mch_122_drum_loop_first_perc.wav"): all 23 slices get correct `label` (KICK/SNARE/HAT/ghost) + spectral breakdown, no manual `file_path` argument needed.
|
|
100
|
+
- **Pivot from M4L bridge to Remote Script TCP** for the file-path lookup. The bridge round-trip surfaced a chunked-response correlation issue under live testing (the second successive `bridge.send_command` returned the *previous* command's payload). The Remote Script handler reads `device.sample.file_path` directly via Live's Python LOM — no UDP packets, no chunk reassembly, no ambiguity. Implementation:
|
|
101
|
+
- `remote_script/LivePilot/simpler_sample.py` — adds `@register("get_simpler_file_path")` handler. Resolves the SimplerDevice (with Drum Rack chain support via optional `chain_index` / `nested_device_index`), reads `device.sample.file_path`, returns `{file_path, track_index, device_index, name, ...}`.
|
|
102
|
+
- `mcp_server/runtime/remote_commands.py` — registers `get_simpler_file_path` in `REMOTE_COMMANDS` (TCP path, primary). The pre-existing entry in `BRIDGE_COMMANDS` stays for forward-compat — `execution_router.classify_step` puts REMOTE_COMMANDS first, so plans route TCP, but the bridge case is still callable as a fallback.
|
|
103
|
+
- `mcp_server/tools/analyzer.py::classify_simpler_slices` — Remote Script TCP call is primary; M4L bridge `bridge.send_command("get_simpler_file_path", …)` is the fallback path. Surfaces the Remote Script's specific error verbatim (e.g. "Simpler.sample.file_path is empty — sample may be embedded") instead of the generic v1.12 message.
|
|
104
|
+
- `m4l_device/livepilot_bridge.js` — `case "get_simpler_file_path"` + `cmd_get_simpler_file_path()` remain in the .amxd freeze for the fallback path.
|
|
105
|
+
- **ff29381 (carried forward)**: `insert_rack_chain` returns `chain_index` so `add_drum_rack_pad` no longer clobbers chain 0 on the second pad. Live-verified against an empty Drum Rack on Ableton 12.4 — three sequential `insert_rack_chain` calls (`chain_index=0`, then `1`, then `0` with `chain_count=3` after position-0 insert).
|
|
106
|
+
|
|
107
|
+
### Improved
|
|
108
|
+
- **CI freshness gate is now source-of-truth-aligned.** The `amxd-freeze-drift` job in `.github/workflows/ci.yml` previously grepped for `"version": "X.Y.Z"` (the runtime ping JSON form), which only landed in the .amxd via post-export binary patching. Since the v1.20-era refactor to `"version": VERSION` (variable reference), every release needed manual byte-patching to satisfy this gate. Now greps for `var VERSION = "X.Y.Z"` — the source-of-truth declaration in `bridge.js` that always survives a Max freeze. No more binary-patching hack required for plain version bumps.
|
|
109
|
+
|
|
110
|
+
### Bridge surface
|
|
111
|
+
- 31 → 32 cases (`get_simpler_file_path` added — used as forward-compat fallback only; primary path is Remote Script TCP).
|
|
112
|
+
- ⚠️ Re-freeze required for the .amxd. New freeze at `m4l_device/LivePilot_Analyzer.amxd` (md5 changed) — distributed to `~/Music/Ableton/User Library/Presets/Audio Effects/Max Audio Effect/` and `~/Documents/Max 9/Library/`. Workflow memory `feedback_amxd_edit_via_maxpat.md` updated to clarify the project-folder JS (`~/Documents/Max 9/Max for Live Devices/<DeviceName> Project/code/livepilot_bridge.js`) is the authoritative path Max freezes from — NOT the user search path `~/Documents/Max 9/Code/`.
|
|
113
|
+
|
|
114
|
+
### Remote Script
|
|
115
|
+
- 191 → 193 handlers. `+1` for `get_simpler_file_path` (this release). The other +1 came from a prior session's reload-handler registration count.
|
|
116
|
+
|
|
117
|
+
### Tests
|
|
118
|
+
- `test_bugfixes_2026_04_25.py` (locks the `chain_index` contract from ff29381) — passes.
|
|
119
|
+
- `test_analyzer_tools.py::test_classify_simpler_slices_returns_error_when_no_file_path` — updated to reflect the v1.23.3 error contract: when both Remote Script and bridge fall back, the Remote Script's specific error (e.g. "Simpler.sample.file_path is empty") is surfaced verbatim.
|
|
120
|
+
- Full suite: 3180 passed, 1 skipped, 0 failed.
|
|
121
|
+
|
|
122
|
+
### Live-test verification log (Ableton 12.4)
|
|
123
|
+
- `classify_simpler_slices(track=4, device=0)` on a 23-slice WAV drum break with no `file_path` argument → returns full classification (KICK/HAT/ghost labels + spectral % per slice). ✓
|
|
124
|
+
- `classify_simpler_slices` with explicit `file_path` argument → bypasses lookup, classifies normally. ✓
|
|
125
|
+
- `insert_rack_chain` end-to-end on empty Drum Rack → `chain_index` derivation correct in all 3 branches (append-on-empty, append-on-N, position-0-on-N). ✓
|
|
126
|
+
|
|
3
127
|
## v1.23.2 — 2026-04-25
|
|
4
128
|
|
|
5
129
|
### Fixed
|
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
|
-
|
|
20
|
+
453 tools. 54 domains. Device atlas. Plan-aware Splice integration. Auto-composition. Spectral perception. Technique memory. Drum-rack pad builder. Live dead-device detection.
|
|
21
21
|
</p>
|
|
22
22
|
|
|
23
23
|
<br>
|
|
@@ -35,12 +35,13 @@
|
|
|
35
35
|
|
|
36
36
|
## What LivePilot Does
|
|
37
37
|
|
|
38
|
-
Most MCP servers are tool collections — they execute commands. LivePilot is an **agentic production system**. It has
|
|
38
|
+
Most MCP servers are tool collections — they execute commands. LivePilot is an **agentic production system**. It has eight layers that work together:
|
|
39
39
|
|
|
40
40
|
| Layer | What it provides |
|
|
41
41
|
|-------|-----------------|
|
|
42
42
|
| **Deterministic Tools** | Direct control: transport, tracks, clips, notes, devices, scenes, mixing, arrangement, browser, automation |
|
|
43
43
|
| **Device Atlas** | Knowledge of every device in Ableton's library — 5264 devices indexed 7 ways (by_id, by_name, by_uri, by_category, by_tag, by_genre, by_pack). 120 enriched with YAML sonic intelligence (47 with aesthetic-tagged `signature_techniques`). 683 drum kits mapped. Free-text `atlas_describe_chain` ("a granular pad like Tim Hecker") and reverse-lookup `atlas_techniques_for_device` cross-reference 146 techniques across 58 devices |
|
|
44
|
+
| **User Corpus** `[v1.23.4+]` | Detects YOUR third-party plugins (VST3 / AU / AUv3 / VST2 / AAX / CLAP / LV2) via filesystem walk + `auval -a`, then auto-synthesizes per-plugin identity profiles (sonic_fingerprint, reach_for, avoid, key_techniques) into the same overlay system the factory atlas uses. The brain stops being limited to Ableton's shipped devices and learns *your* library — Valhalla, Glitchmachines, Cem Olcay, ChowDSP, Moog, your custom .adg racks, your Max for Live devices. Same query → different recommendations per user. **14 `corpus_*` tools.** See [User Corpus](#user-corpus--14-tools-v1234) below |
|
|
44
45
|
| **Concept Surface** | Two reference files let the LLM's training translate into LivePilot: `artist-vocabularies.md` maps ~25 producers (Villalobos, Hawtin, Basic Channel, Gas, Basinski, Hecker, Aphex, Autechre, Dilla, Burial, Henke, Daft Punk, …) to `reach_for` / `avoid` / `key_techniques`; `genre-vocabularies.md` maps 15 genres to tempo / kick / bass / percussion / harmonic / texture / devices. The LLM reads "sound like Gas" and gets a concrete device chain, not guesswork |
|
|
45
46
|
| **Sample Engine** | Three-source sample intelligence — Ableton's browser, your filesystem, and Splice's catalog (plan-aware: Ableton Live plan uses daily quota, Sounds+/Creator uses credits, free samples bypass both). 6 fitness critics. 29 processing techniques. Collections, presets, preview-URL audition, LIVE Describe-a-Sound + Variations via Splice GraphQL |
|
|
46
47
|
| **Spectral Perception** | Real-time ears via M4L — 9-band FFT (with sub_low split at 20-60 Hz for kick fundamentals), RMS/peak metering, Krumhansl-Schmuckler key detection, pitch tracking, FluCoMa mel/chroma/onset. Auto-loaded via `ensure_analyzer_on_master` (v1.20.3) — no more silently-degraded mix moves from forgotten analyzer |
|
|
@@ -51,6 +52,30 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
51
52
|
|
|
52
53
|
---
|
|
53
54
|
|
|
55
|
+
## Two Ways to Talk to LivePilot
|
|
56
|
+
|
|
57
|
+
Pick whichever is faster for the idea in your head — both reach the same 453-tool surface.
|
|
58
|
+
|
|
59
|
+
### Route A — Artist / aesthetic shorthand
|
|
60
|
+
|
|
61
|
+
> *"Sound like J Dilla."* *"Make this feel more like Burial."* *"BoC-style pads."*
|
|
62
|
+
|
|
63
|
+
The Concept Surface (`artist-vocabularies.md` + `genre-vocabularies.md`) maps ~25 producers and 15 genres to concrete `reach_for` / `avoid` / `key_techniques` lists. An artist name becomes a queryable label for a cluster of techniques. Useful when you know the aesthetic but not the parameters, or when one word is faster than the half-paragraph of reverb / sidechain / pitch-bend settings it implies.
|
|
64
|
+
|
|
65
|
+
### Route B — Direct musical intent
|
|
66
|
+
|
|
67
|
+
> *"Humanize the drum loop: 62% swing on the 16th hats, snare landing 4 ms ahead of the 2 and 4 for forward push, ghost snares filling every off-16th at velocity 25–40, kick locked to the grid, and add ±2 ms timing jitter to everything except the kick. EQ a 3 dB notch at 380 Hz on the snare to pull it back from the bass."*
|
|
68
|
+
|
|
69
|
+
The full Live Object Model is exposed. Swing percentages, micro-timing offsets in milliseconds, dB cuts, frequency ranges, modulation depths, envelope shapes, send levels, automation curves, scale degrees, voice leading — anything the LOM allows, plus the 44 semantic moves on top.
|
|
70
|
+
|
|
71
|
+
### Mixing the routes
|
|
72
|
+
|
|
73
|
+
Most sessions do both. Lead with shorthand to anchor the aesthetic, then refine with millisecond-precision intent once the shape is roughed in. Every artist tag resolves to moves you can also call directly — the shorthand is a convenience layer over the same parameters you reach with Route B.
|
|
74
|
+
|
|
75
|
+
<br>
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
54
79
|
## Architecture
|
|
55
80
|
|
|
56
81
|
```
|
|
@@ -82,8 +107,8 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
82
107
|
│ └─────────────────┼──────────────────┘ │
|
|
83
108
|
│ ▼ │
|
|
84
109
|
│ ┌─────────────────┐ │
|
|
85
|
-
│ │
|
|
86
|
-
│ │
|
|
110
|
+
│ │ 453 MCP Tools │ │
|
|
111
|
+
│ │ 54 domains │ │
|
|
87
112
|
│ └────────┬────────┘ │
|
|
88
113
|
│ │ │
|
|
89
114
|
│ Remote Script ──┤── TCP 9878 │
|
|
@@ -103,7 +128,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
103
128
|
|
|
104
129
|
**MCP Server** (`mcp_server/`) — Python FastMCP server. Validates inputs, routes commands to the Remote Script over TCP, manages the M4L bridge, runs the atlas, sample engine, composer, and all intelligence engines. This is what your AI client connects to.
|
|
105
130
|
|
|
106
|
-
**M4L Bridge** (`m4l_device/`) — Optional Max for Live Audio Effect on the master track. Provides deep LOM access through Max's LiveAPI that the ControlSurface API can't reach. UDP 9880 (M4L to server) carries spectral data and LiveAPI responses. OSC 9881 (server to M4L) sends commands. The 38 spectral/analyzer tools strictly require the bridge; device and sample tools that call the bridge also have graceful fallbacks, so core functionality works without it. Backed by
|
|
131
|
+
**M4L Bridge** (`m4l_device/`) — Optional Max for Live Audio Effect on the master track. Provides deep LOM access through Max's LiveAPI that the ControlSurface API can't reach. UDP 9880 (M4L to server) carries spectral data and LiveAPI responses. OSC 9881 (server to M4L) sends commands. The 38 spectral/analyzer tools strictly require the bridge; device and sample tools that call the bridge also have graceful fallbacks, so core functionality works without it. Backed by 32 bridge commands for hidden parameters, Simpler internals, warp markers, display values, and Simpler warp / Compressor sidechain writes that live on child objects Python can't reach.
|
|
107
132
|
|
|
108
133
|
**Device Atlas** (`mcp_server/atlas/`) — In-memory indexed JSON database. 5264 devices with browser URIs (bundled baseline), 120 enriched with YAML sonic intelligence profiles (mood, genre, texture, recommended chains). 7 indexes: by_id, by_name, by_uri, by_category, by_tag, by_genre, by_pack. Reverse-index `device_techniques_index.json` powers `atlas_techniques_for_device` (146 cross-references across 58 devices). The AI never hallucinates a device name or preset — it always resolves against the atlas first. **v1.22.0+**: run `scan_full_library` after install to index YOUR packs + User Library + plugins into `~/.livepilot/atlas/device_atlas.json` — your personal atlas overrides the baseline and survives npm updates.
|
|
109
134
|
|
|
@@ -123,7 +148,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
123
148
|
|
|
124
149
|
## The Intelligence Layer
|
|
125
150
|
|
|
126
|
-
12 engines sit on top of the
|
|
151
|
+
12 engines sit on top of the 453 tools. They give the AI musical judgment, not just musical execution.
|
|
127
152
|
|
|
128
153
|
### SongBrain — What the Song Is
|
|
129
154
|
|
|
@@ -175,7 +200,7 @@ Every engine follows: **measure before → act → measure after → compare**.
|
|
|
175
200
|
|
|
176
201
|
## Tools
|
|
177
202
|
|
|
178
|
-
|
|
203
|
+
453 tools across 54 domains. Highlights below — [full catalog here](docs/manual/tool-catalog.md).
|
|
179
204
|
|
|
180
205
|
<br>
|
|
181
206
|
|
|
@@ -202,7 +227,7 @@ Every engine follows: **measure before → act → measure after → compare**.
|
|
|
202
227
|
|
|
203
228
|
<br>
|
|
204
229
|
|
|
205
|
-
### M4L Bridge — 38 analyzer tools `[optional]`,
|
|
230
|
+
### M4L Bridge — 38 analyzer tools `[optional]`, 32 bridge commands
|
|
206
231
|
|
|
207
232
|
The M4L Analyzer sits on the master track. UDP 9880 carries spectral data to the server. OSC 9881 sends commands back. The `ensure_analyzer_on_master` pre-flight (v1.20.3) loads the analyzer idempotently on first use — call it once at session start and forget about it.
|
|
208
233
|
|
|
@@ -257,10 +282,83 @@ reload_atlas Hot-reload the atlas after adding enrichments
|
|
|
257
282
|
extension_atlas_search [v1.23.0+] Search user-local atlas overlays
|
|
258
283
|
extension_atlas_get [v1.23.0+] Fetch a single overlay entry by namespace
|
|
259
284
|
extension_atlas_list [v1.23.0+] Enumerate overlay namespaces + entity_type counts
|
|
285
|
+
|
|
286
|
+
# Pack-Atlas Phase C-F (v1.23.4+) — corpus-driven orchestration
|
|
287
|
+
atlas_macro_fingerprint [v1.23.4+] "More like this" — find similar presets across 3,813 sidecars by macro fingerprint
|
|
288
|
+
atlas_transplant [v1.23.4+] Adapt a demo / preset / workflow to new BPM, scale, or aesthetic — PRESERVE / SCALE / REMAP / REPLACE decisions
|
|
289
|
+
atlas_demo_story [v1.23.4+] Track-by-track narrative + production sequence inference for any of 104 factory demo .als
|
|
290
|
+
atlas_extract_chain [v1.23.4+] Surgically rebuild a demo track's device chain as an executable plan (load_browser_item + insert_device + set_device_parameter)
|
|
291
|
+
atlas_pack_aware_compose [v1.23.4+] Bootstrap a project with pack-coherent track selection from an aesthetic brief; supports `pack_diversity="eclectic"` mode
|
|
292
|
+
atlas_cross_pack_chain [v1.23.4+] Execute any of 15 cross-pack workflow recipes step-by-step with aesthetic overrides (target_scale / target_bpm / transpose_semitones)
|
|
260
293
|
```
|
|
261
294
|
|
|
262
295
|
**v1.23.0 — User-local extensions:** Drop YAML files at `~/.livepilot/atlas-overlays/<namespace>/` to extend the atlas with custom hardware libraries, signature chains, or technique recipes — survives npm updates. See [`docs/EXTENSION_API.md`](docs/EXTENSION_API.md).
|
|
263
296
|
|
|
297
|
+
**v1.23.4 — Pack-Atlas Phases C/D/E/F:** Six new corpus-driven orchestration tools turn the 3,917 parsed pack sidecars + 104 demo `.als` parses into actionable artifacts — find similar presets, transplant aesthetics across BPM/scale/genre, narrate a demo, extract a track's chain as a runnable plan, bootstrap pack-coherent compositions, run any of 15 cross-pack workflow recipes. All execution is dry-run by default — returns plans, doesn't auto-mutate the session.
|
|
298
|
+
|
|
299
|
+
<br>
|
|
300
|
+
|
|
301
|
+
### User Corpus — 14 tools `[v1.23.4+]`
|
|
302
|
+
|
|
303
|
+
> **Why this exists.** The factory atlas (5264 devices, 33 packs) is what *Ableton ships*. Your real library is bigger — your VST/AU plugins, your Max for Live devices, your `.adg` racks, your custom presets, your Splice packs. Without the corpus builder, all of that is invisible to LivePilot. With it, the same query that previously routed to Operator + Saturator can route to *your* Valhalla Supermassive, *your* CHOWTapeModel, *your* Moog Model D — because LivePilot now knows what you have, what each tool sounds like, and which producer aesthetics it supports.
|
|
304
|
+
|
|
305
|
+
The corpus builder is a 4-phase pipeline that turns "what's installed on this Mac" into AI-queryable knowledge:
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
Phase 1 — DETECT Walk plugin folders + run `auval -a` for AUv3 / Mac Catalyst
|
|
309
|
+
coverage. Captures format (VST3/AU/AAX/CLAP/LV2),
|
|
310
|
+
vendor, version, bundle ID. ~40-200 plugins typical.
|
|
311
|
+
|
|
312
|
+
Phase 2 — CANONICALIZE Dedupe by vendor+name, prefer VST3 over AU, strip vendor
|
|
313
|
+
suffix variants ("Valhalla DSP, LLC" = "Valhalladsp" =
|
|
314
|
+
"Valhalla DSP"). Cluster by vendor for batch research.
|
|
315
|
+
|
|
316
|
+
Phase 3 — RESEARCH Discover local manual files (PDFs, READMEs) per plugin.
|
|
317
|
+
Emit WebSearch task packets for plugin+technique research.
|
|
318
|
+
|
|
319
|
+
Phase 4 — SYNTHESIZE Sonnet subagent dispatch — write per-plugin identity.yaml
|
|
320
|
+
with sonic_fingerprint / reach_for / avoid / key_techniques /
|
|
321
|
+
parameter_glossary / comparable_plugins / genre_affinity /
|
|
322
|
+
producer_anchors. EXACTLY ONE primary format tag (no
|
|
323
|
+
dual-indexing across formats).
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The result lives at `~/.livepilot/atlas-overlays/user/plugins/<plugin_id>/identity.yaml` and is loaded by every reasoning tool — `atlas_search`, `atlas_chain_suggest`, `atlas_macro_fingerprint`, `atlas_describe_chain` — alongside the factory atlas. Each result is tagged with its source (`factory_atlas` vs `user_overlay:user`), so the agent always knows whether it's recommending Ableton stock or your own gear.
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
corpus_setup_wizard One-shot orchestration — runs the full pipeline
|
|
330
|
+
corpus_init Initialize ~/.livepilot/corpus/ + manifest.yaml
|
|
331
|
+
corpus_status Inspect manifest, sources, scan history
|
|
332
|
+
corpus_list_scanners Enumerate registered scanner types
|
|
333
|
+
corpus_add_source Register a new scan source (project / racks / Max / samples)
|
|
334
|
+
corpus_remove_source Remove a scan source from manifest
|
|
335
|
+
corpus_scan Run scanners on configured sources
|
|
336
|
+
corpus_detect_plugins Phase 1 — VST3 / AU / AUv3 / VST2 / AAX / LV2 detection
|
|
337
|
+
corpus_canonicalize_plugins Phase 2 — dedupe + VST3-preferred + suffix strip
|
|
338
|
+
corpus_cluster_plugins Phase 2.5 — group by vendor for efficient research dispatch
|
|
339
|
+
corpus_trim_plugin_identity Slim a yaml to the overlay-required minimum
|
|
340
|
+
corpus_discover_manuals Phase 3 — locate local PDFs / READMEs per plugin
|
|
341
|
+
corpus_research_targets Phase 3 — emit WebSearch task packet for the agent
|
|
342
|
+
corpus_emit_synthesis_briefs Phase 4 — emit sonnet-subagent briefs per plugin
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Why versatility outside Ableton matters.** A static knowledge base ages out the day you install a new plugin. The corpus builder makes LivePilot's knowledge boundary equal to *your library*, not *Ableton's library*. Every plugin you add can be re-scanned and synthesized in minutes; every saved `.adg` rack you build can be indexed alongside Ableton's factory chains. The brain becomes specifically yours.
|
|
346
|
+
|
|
347
|
+
**Quick start (3 commands):**
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# In your MCP client (Claude Code / Desktop / Cursor):
|
|
351
|
+
corpus_setup_wizard # one-shot orchestration
|
|
352
|
+
# OR fine-grained control:
|
|
353
|
+
corpus_detect_plugins use_auval=true # finds AUv3 / Mac Catalyst plugins
|
|
354
|
+
corpus_canonicalize_plugins # VST3 preference + vendor dedup
|
|
355
|
+
corpus_cluster_plugins # vendor-grouped clusters
|
|
356
|
+
corpus_research_targets # → agent runs WebSearch
|
|
357
|
+
corpus_emit_synthesis_briefs # → sonnet writes identity.yamls
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
See [`docs/USER_CORPUS_GUIDE.md`](docs/USER_CORPUS_GUIDE.md) for full walk-through, [`docs/PLUGIN_KNOWLEDGE_ENGINE.md`](docs/PLUGIN_KNOWLEDGE_ENGINE.md) for engine internals, and [`livepilot/skills/livepilot-corpus-builder/SKILL.md`](livepilot/skills/livepilot-corpus-builder/SKILL.md) for the agent skill that drives the pipeline.
|
|
361
|
+
|
|
264
362
|
<br>
|
|
265
363
|
|
|
266
364
|
### Sample Engine — 23 tools
|
|
@@ -396,7 +494,7 @@ The V2 intelligence layer. These tools analyze, diagnose, plan, evaluate, and le
|
|
|
396
494
|
| Creative Constraints | 5 | constraint activation, reference-inspired variants |
|
|
397
495
|
| Preview Studio | 5 | variant creation, preview rendering, comparison, commit |
|
|
398
496
|
|
|
399
|
-
> **[View all
|
|
497
|
+
> **[View all 453 tools →](docs/manual/tool-catalog.md)**
|
|
400
498
|
|
|
401
499
|
<br>
|
|
402
500
|
|
|
@@ -623,7 +721,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for architecture details, code guidelines
|
|
|
623
721
|
|
|
624
722
|
| Document | What's inside |
|
|
625
723
|
|----------|---------------|
|
|
626
|
-
| [Manual](docs/manual/index.md) | Complete reference: architecture, all
|
|
724
|
+
| [Manual](docs/manual/index.md) | Complete reference: architecture, all 453 tools, workflows |
|
|
627
725
|
| [Intelligence Layer](docs/manual/intelligence.md) | How the 12 engines connect — conductor, moves, preview, evaluation |
|
|
628
726
|
| [Device Atlas](docs/manual/device-atlas.md) | 5264 devices indexed — search, suggest, chain building |
|
|
629
727
|
| [Samples & Slicing](docs/manual/samples.md) | 3-source search, fitness critics, slice workflows |
|
|
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.23.
|
|
37
|
+
var VERSION = "1.23.4";
|
|
38
38
|
|
|
39
39
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
40
40
|
|
|
@@ -142,6 +142,9 @@ function dispatch(cmd, args) {
|
|
|
142
142
|
case "get_simpler_slices":
|
|
143
143
|
cmd_get_simpler_slices(args);
|
|
144
144
|
break;
|
|
145
|
+
case "get_simpler_file_path":
|
|
146
|
+
cmd_get_simpler_file_path(args);
|
|
147
|
+
break;
|
|
145
148
|
case "crop_simpler":
|
|
146
149
|
cmd_simpler_action(args, "crop");
|
|
147
150
|
break;
|
|
@@ -975,6 +978,41 @@ function cmd_get_simpler_slices(args) {
|
|
|
975
978
|
});
|
|
976
979
|
}
|
|
977
980
|
|
|
981
|
+
function cmd_get_simpler_file_path(args) {
|
|
982
|
+
// Resolves the absolute file path of a Simpler's loaded sample.
|
|
983
|
+
// Mirrors cmd_get_clip_file_path's shape so analyzer.py can route both
|
|
984
|
+
// through the same response handler. Closes the v1.12 follow-up that
|
|
985
|
+
// left classify_simpler_slices unable to do its primary job
|
|
986
|
+
// (returning slice geometry without classification labels) when
|
|
987
|
+
// file_path wasn't passed explicitly.
|
|
988
|
+
var track_idx = parseInt(args[0]);
|
|
989
|
+
var device_idx = parseInt(args[1]);
|
|
990
|
+
var path = build_device_path(track_idx, device_idx);
|
|
991
|
+
|
|
992
|
+
cursor_a.goto(path);
|
|
993
|
+
if (cursor_a.get("class_name").toString() !== "OriginalSimpler") {
|
|
994
|
+
send_response({"error": "Not a Simpler device"});
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
try {
|
|
999
|
+
cursor_b.goto(path + " sample");
|
|
1000
|
+
var sample_path = cursor_b.get("file_path").toString();
|
|
1001
|
+
if (!sample_path || sample_path === "0") {
|
|
1002
|
+
send_response({"error": "Simpler has no sample loaded"});
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
send_response({
|
|
1006
|
+
"track": track_idx,
|
|
1007
|
+
"device": device_idx,
|
|
1008
|
+
"file_path": _to_posix_path(sample_path),
|
|
1009
|
+
"name": cursor_a.get("name").toString()
|
|
1010
|
+
});
|
|
1011
|
+
} catch(e) {
|
|
1012
|
+
send_response({"error": "Failed to read Simpler sample path: " + e.message});
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
978
1016
|
function cmd_simpler_action(args, action) {
|
|
979
1017
|
var track_idx = parseInt(args[0]);
|
|
980
1018
|
var device_idx = parseInt(args[1]);
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.23.
|
|
2
|
+
__version__ = "1.23.4"
|