livepilot 1.26.0 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +1 -1
- package/installer/codex.js +87 -9
- package/livepilot/.Codex-plugin/plugin.json +8 -0
- package/livepilot/.claude-plugin/plugin.json +8 -0
- package/livepilot/.mcp.json +8 -0
- package/livepilot/agents/livepilot-producer/AGENT.md +314 -0
- package/livepilot/commands/arrange.md +47 -0
- package/livepilot/commands/beat.md +81 -0
- package/livepilot/commands/evaluate.md +49 -0
- package/livepilot/commands/memory.md +22 -0
- package/livepilot/commands/mix.md +47 -0
- package/livepilot/commands/perform.md +42 -0
- package/livepilot/commands/session.md +13 -0
- package/livepilot/commands/sounddesign.md +58 -0
- package/livepilot/rubrics/default_preset_check.md +82 -0
- package/livepilot/rubrics/layer_accumulation.md +79 -0
- package/livepilot/rubrics/layer_precision.md +79 -0
- package/livepilot/rubrics/modulation_presence.md +63 -0
- package/livepilot/rubrics/sound_design_depth.md +40 -0
- package/livepilot/skills/livepilot-arrangement/SKILL.md +164 -0
- package/livepilot/skills/livepilot-composition-engine/SKILL.md +151 -0
- package/livepilot/skills/livepilot-composition-engine/references/form-patterns.md +97 -0
- package/livepilot/skills/livepilot-composition-engine/references/transition-archetypes.md +102 -0
- package/livepilot/skills/livepilot-core/SKILL.md +261 -0
- package/livepilot/skills/livepilot-core/references/ableton-workflow-patterns.md +831 -0
- package/livepilot/skills/livepilot-core/references/affordances/_schema.md +160 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/auto-filter.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/chorus-ensemble.yaml +91 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/compressor.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/convolution-reverb.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/corpus.yaml +84 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/drift.yaml +105 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/echo.yaml +108 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/eq-eight.yaml +95 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/glue-compressor.yaml +88 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/granulator-iii.yaml +104 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/hybrid-reverb.yaml +83 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/operator.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/ping-pong-delay.yaml +104 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/poli.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/saturator.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/shifter.yaml +77 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/simpler.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/utility.yaml +95 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/vinyl-distortion.yaml +92 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/wavetable.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/artist-vocabularies.md +389 -0
- package/livepilot/skills/livepilot-core/references/automation-atlas.md +272 -0
- package/livepilot/skills/livepilot-core/references/concepts/_schema.md +158 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/akufen.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/aphex-twin.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/arca-sophie.yaml +131 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/autechre.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/basic-channel.yaml +140 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/basinski.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/boards-of-canada.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/burial.yaml +127 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/com-truise-tycho.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/daft-punk.yaml +117 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/dj-premier-rza.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/gas.yaml +134 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/hawtin.yaml +127 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/isolee-luomo.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/j-dilla.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/jeff-mills.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/johannsson-richter.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/madlib.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/moodymann-theo-parrish.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/oneohtrix-point-never.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/photek-source-direct.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/rashad-spinn-traxman.yaml +122 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/robert-henke.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/shackleton.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/skream-mala.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/stars-of-the-lid.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/tim-hecker.yaml +122 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/villalobos.yaml +135 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/ambient.yaml +137 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/boom_bap.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/deep-minimal.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/deep_house.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/detroit_techno.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/disco.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/downtempo.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/drone.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/drum-and-bass.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dub-techno.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dub.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dubstep.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/experimental.yaml +136 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/footwork.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/hip-hop.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/house.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/hyperpop.yaml +128 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/idm.yaml +134 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/lo_fi.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/microhouse.yaml +138 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/minimal-techno.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/modern-classical.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/soul.yaml +125 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/synthwave.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/techno.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/trap.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/uk-garage.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/00-index.md +110 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/distortion-and-character.md +687 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/drums-and-percussion.md +753 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/dynamics-and-punch.md +525 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/eq-and-filtering.md +402 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/midi-tools.md +963 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/movement-and-modulation.md +874 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/space-and-depth.md +571 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/spectral-and-weird.md +714 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/synths-native.md +953 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +34 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +204 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +173 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +211 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +188 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +162 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +229 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +243 -0
- package/livepilot/skills/livepilot-core/references/genre-vocabularies.md +382 -0
- package/livepilot/skills/livepilot-core/references/m4l-devices.md +352 -0
- package/livepilot/skills/livepilot-core/references/memory-guide.md +178 -0
- package/livepilot/skills/livepilot-core/references/midi-recipes.md +402 -0
- package/livepilot/skills/livepilot-core/references/mixing-patterns.md +578 -0
- package/livepilot/skills/livepilot-core/references/overview.md +300 -0
- package/livepilot/skills/livepilot-core/references/pack-knowledge.md +319 -0
- package/livepilot/skills/livepilot-core/references/sample-manipulation.md +724 -0
- package/livepilot/skills/livepilot-core/references/sound-design-deep.md +140 -0
- package/livepilot/skills/livepilot-core/references/sound-design.md +393 -0
- package/livepilot/skills/livepilot-corpus-builder/SKILL.md +379 -0
- package/livepilot/skills/livepilot-creative-director/SKILL.md +455 -0
- package/livepilot/skills/livepilot-creative-director/references/anti-repetition-rules.md +214 -0
- package/livepilot/skills/livepilot-creative-director/references/creative-brief-template.md +222 -0
- package/livepilot/skills/livepilot-creative-director/references/hybrid-compilation.md +185 -0
- package/livepilot/skills/livepilot-creative-director/references/move-family-diversity-rule.md +258 -0
- package/livepilot/skills/livepilot-creative-director/references/phase-6-execution.md +409 -0
- package/livepilot/skills/livepilot-creative-director/references/the-four-move-rule.md +192 -0
- package/livepilot/skills/livepilot-devices/SKILL.md +213 -0
- package/livepilot/skills/livepilot-devices/references/load_browser_item-uri-grammar.md +82 -0
- package/livepilot/skills/livepilot-evaluation/SKILL.md +195 -0
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +176 -0
- package/livepilot/skills/livepilot-evaluation/references/evaluation-contracts.md +121 -0
- package/livepilot/skills/livepilot-evaluation/references/memory-promotion.md +110 -0
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +136 -0
- package/livepilot/skills/livepilot-mix-engine/references/mix-critics.md +143 -0
- package/livepilot/skills/livepilot-mix-engine/references/mix-moves.md +105 -0
- package/livepilot/skills/livepilot-mixing/SKILL.md +157 -0
- package/livepilot/skills/livepilot-notes/SKILL.md +130 -0
- package/livepilot/skills/livepilot-performance-engine/SKILL.md +122 -0
- package/livepilot/skills/livepilot-performance-engine/references/performance-safety.md +98 -0
- package/livepilot/skills/livepilot-release/SKILL.md +151 -0
- package/livepilot/skills/livepilot-sample-engine/SKILL.md +117 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +87 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +51 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +131 -0
- package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +225 -0
- package/livepilot/skills/livepilot-sound-design-engine/references/patch-model.md +119 -0
- package/livepilot/skills/livepilot-sound-design-engine/references/sound-design-critics.md +118 -0
- package/livepilot/skills/livepilot-wonder/SKILL.md +143 -0
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/LivePilot_Elektron.amxd +0 -0
- package/m4l_device/LivePilot_Elektron.maxpat +758 -0
- package/m4l_device/livepilot_bridge.js +1 -1
- package/m4l_device/livepilot_elektron_bridge.js +82 -0
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/composer/develop/apply.py +1 -1
- package/mcp_server/composer/full/apply.py +32 -6
- package/mcp_server/m4l_bridge.py +5 -0
- package/mcp_server/runtime/execution_router.py +6 -0
- package/mcp_server/runtime/mcp_dispatch.py +18 -0
- package/mcp_server/runtime/remote_commands.py +2 -0
- package/mcp_server/server.py +11 -7
- package/package.json +20 -5
- package/remote_script/LivePilot/__init__.py +1 -1
- package/remote_script/LivePilot/server.py +63 -2
- package/requirements.txt +3 -3
- package/server.json +3 -3
|
@@ -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.26.
|
|
37
|
+
var VERSION = "1.26.1";
|
|
38
38
|
|
|
39
39
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
40
40
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// m4l_device/livepilot_elektron_bridge.js
|
|
2
|
+
// LivePilot Elektron Bridge — runs inside LivePilot_Elektron.amxd.
|
|
3
|
+
//
|
|
4
|
+
// Wire model:
|
|
5
|
+
//
|
|
6
|
+
// M4L → Python : UDP 9882
|
|
7
|
+
// Inbound SysEx from physical MIDI [sysexin → sxformat
|
|
8
|
+
// → prepend sysex] arrives at JS as a "sysex <bytes...>"
|
|
9
|
+
// message; forwards out outlet 1 (→ [udpsend 9882]).
|
|
10
|
+
//
|
|
11
|
+
// Python → M4L : UDP 9883
|
|
12
|
+
// [udpreceive 9883] outputs bytes as a "list" message
|
|
13
|
+
// → JS function list() pushes onto sendQueue.
|
|
14
|
+
// [metro 50 @active 1] drives bang() which drains one
|
|
15
|
+
// chunk per tick onto outlet 0 (→ [midiout]).
|
|
16
|
+
//
|
|
17
|
+
// Outlets:
|
|
18
|
+
// 0 → [midiout] paced chunks to physical MIDI port
|
|
19
|
+
// 1 → [udpsend 127.0.0.1 9882] sysex-from-device upstream to Python
|
|
20
|
+
// 2 → "set <text>" → live.text status display
|
|
21
|
+
// 3 → +1 counter → live.numbox RX message counter
|
|
22
|
+
//
|
|
23
|
+
// Phase 1 design note: heartbeat is intentionally OUT for v1 of the M4L
|
|
24
|
+
// device. The Python bridge uses per-operation timeouts (per design
|
|
25
|
+
// spec §7.3) so it does not need M4L liveness polling. Heartbeat / pong
|
|
26
|
+
// can be added in a Phase 2 patch to the .maxpat if "is M4L loaded?"
|
|
27
|
+
// detection becomes useful — the ping()/pong() functions below are
|
|
28
|
+
// kept as reserved stubs for that future wiring.
|
|
29
|
+
|
|
30
|
+
inlets = 1;
|
|
31
|
+
outlets = 4;
|
|
32
|
+
|
|
33
|
+
var sendQueue = [];
|
|
34
|
+
var rxCount = 0;
|
|
35
|
+
|
|
36
|
+
// Called by [metro 50 @active 1] — drain one queued chunk per tick.
|
|
37
|
+
function bang() {
|
|
38
|
+
if (sendQueue.length > 0) {
|
|
39
|
+
var chunk = sendQueue.shift();
|
|
40
|
+
// Spread chunk into outlet args so Max sees it as a list message
|
|
41
|
+
outlet.apply(this, [0].concat(chunk));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Called by [udpreceive 9883] — outputs raw UDP bytes as a list.
|
|
46
|
+
// This is the Python → M4L outbound MIDI path. Each datagram is a
|
|
47
|
+
// pre-chunked SysEx fragment; we queue and let bang() pace them.
|
|
48
|
+
function list() {
|
|
49
|
+
var bytes = [];
|
|
50
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
51
|
+
bytes.push(arguments[i]);
|
|
52
|
+
}
|
|
53
|
+
sendQueue.push(bytes);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Called when [sysexin → sxformat → prepend sysex] delivers a complete
|
|
57
|
+
// SysEx as a "sysex <bytes...>" message. We forward to Python and
|
|
58
|
+
// bump the RX counter + status.
|
|
59
|
+
function sysex() {
|
|
60
|
+
var bytes = [];
|
|
61
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
62
|
+
bytes.push(arguments[i]);
|
|
63
|
+
}
|
|
64
|
+
// Forward to Python via outlet 1 → [udpsend 9882]
|
|
65
|
+
outlet.apply(this, [1].concat(bytes));
|
|
66
|
+
// Bump RX counter via outlet 3
|
|
67
|
+
rxCount += 1;
|
|
68
|
+
outlet(3, rxCount);
|
|
69
|
+
// Update status via outlet 2
|
|
70
|
+
outlet(2, "set", "Online — receiving SysEx");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Phase 2 reserved: heartbeat ping. Wire [metro 1000] → [t ping] → js
|
|
74
|
+
// to enable. Not wired in Phase 1 .maxpat.
|
|
75
|
+
function ping() {
|
|
76
|
+
outlet(1, 0xF0, 0x7F, 0x7F, 0x00, 0xF7);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Phase 2 reserved: receive pong from Python. Currently unused.
|
|
80
|
+
function pong() {
|
|
81
|
+
outlet(2, "set", "Online — pong received");
|
|
82
|
+
}
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.26.
|
|
2
|
+
__version__ = "1.26.1"
|
|
@@ -64,7 +64,7 @@ async def _bridge_ping_stub(ctx: Any) -> dict:
|
|
|
64
64
|
bridge = ctx.lifespan_context.get("m4l_bridge")
|
|
65
65
|
if bridge is None:
|
|
66
66
|
raise RuntimeError("bridge not available")
|
|
67
|
-
return await bridge.send_command("ping",
|
|
67
|
+
return await bridge.send_command("ping", timeout=0.5)
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
async def _back_to_arranger(ctx: Any) -> dict:
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
import re as _re
|
|
7
|
+
import inspect
|
|
7
8
|
import time
|
|
8
9
|
|
|
9
10
|
from fastmcp import Context
|
|
@@ -92,6 +93,28 @@ _TONAL_ROLES_ALWAYS_WARP: frozenset[str] = frozenset({
|
|
|
92
93
|
})
|
|
93
94
|
|
|
94
95
|
|
|
96
|
+
async def _call_mcp_analysis_tool(ctx: Context, tool: str, params: dict) -> dict:
|
|
97
|
+
"""Dispatch analyzer/intelligence tools through the MCP registry.
|
|
98
|
+
|
|
99
|
+
These tools are Python MCP tools, not Remote Script TCP handlers. Keeping
|
|
100
|
+
full-mode analysis on the registry path prevents creative plans from
|
|
101
|
+
passing tests against mocks and then failing in Live as unknown commands.
|
|
102
|
+
"""
|
|
103
|
+
lifespan = getattr(ctx, "lifespan_context", {}) or {}
|
|
104
|
+
registry = lifespan.get("mcp_dispatch")
|
|
105
|
+
if registry is None:
|
|
106
|
+
from ...runtime.mcp_dispatch import build_mcp_dispatch_registry
|
|
107
|
+
registry = build_mcp_dispatch_registry()
|
|
108
|
+
|
|
109
|
+
fn = registry.get(tool) if registry else None
|
|
110
|
+
if fn is None:
|
|
111
|
+
return {"error": f"MCP analysis tool '{tool}' is not registered"}
|
|
112
|
+
|
|
113
|
+
call = fn(params, ctx=ctx)
|
|
114
|
+
result = await call if inspect.isawaitable(call) else call
|
|
115
|
+
return result if isinstance(result, dict) else {"result": result}
|
|
116
|
+
|
|
117
|
+
|
|
95
118
|
def _decide_warp_loops(
|
|
96
119
|
role: str,
|
|
97
120
|
file_path: str,
|
|
@@ -825,8 +848,9 @@ async def apply_full_plan_v2(ctx: Context, plan: dict) -> dict:
|
|
|
825
848
|
# Goal: give the agent acoustic characteristics of the loaded sound so
|
|
826
849
|
# it can reason about fit. ONLY static analysis here (no playback);
|
|
827
850
|
# active solo-trigger analysis is Scope B / v1.25.
|
|
828
|
-
# Analysis is
|
|
829
|
-
#
|
|
851
|
+
# Analysis is MCP-side intelligence, not a Remote Script TCP command.
|
|
852
|
+
# Route through the MCP dispatch registry so live execution matches
|
|
853
|
+
# the same boundary the async plan router uses.
|
|
830
854
|
role = track_spec.get("role", "")
|
|
831
855
|
instrument_uri = (track_spec.get("instrument") or {}).get("uri", "")
|
|
832
856
|
layer_analysis: dict = {"status": "skipped", "reason": "no analyzer applicable"}
|
|
@@ -834,7 +858,8 @@ async def apply_full_plan_v2(ctx: Context, plan: dict) -> dict:
|
|
|
834
858
|
if instrument_uri.startswith(("query:Synths#", "query:Sounds#")):
|
|
835
859
|
# Synth / preset — analyze the patch
|
|
836
860
|
try:
|
|
837
|
-
patch_result =
|
|
861
|
+
patch_result = await _call_mcp_analysis_tool(
|
|
862
|
+
ctx,
|
|
838
863
|
"analyze_synth_patch",
|
|
839
864
|
{"track_index": track_index, "device_index": 0},
|
|
840
865
|
)
|
|
@@ -854,7 +879,8 @@ async def apply_full_plan_v2(ctx: Context, plan: dict) -> dict:
|
|
|
854
879
|
any(instrument_uri.lower().endswith(ext) for ext in (".aif", ".wav", ".mp3", ".flac")):
|
|
855
880
|
# Sample-based — analyze via track reference (no file_path needed)
|
|
856
881
|
try:
|
|
857
|
-
sample_result =
|
|
882
|
+
sample_result = await _call_mcp_analysis_tool(
|
|
883
|
+
ctx,
|
|
858
884
|
"analyze_sample",
|
|
859
885
|
{"track_index": track_index, "clip_index": 0},
|
|
860
886
|
)
|
|
@@ -1034,10 +1060,10 @@ async def apply_full_plan_v2(ctx: Context, plan: dict) -> dict:
|
|
|
1034
1060
|
# session state.
|
|
1035
1061
|
mix_analysis: dict = {"status": "skipped", "reason": "not run"}
|
|
1036
1062
|
try:
|
|
1037
|
-
mix_result =
|
|
1063
|
+
mix_result = await _call_mcp_analysis_tool(ctx, "analyze_mix", {})
|
|
1038
1064
|
if isinstance(mix_result, dict) and not mix_result.get("error"):
|
|
1039
1065
|
try:
|
|
1040
|
-
masking_result =
|
|
1066
|
+
masking_result = await _call_mcp_analysis_tool(ctx, "get_masking_report", {})
|
|
1041
1067
|
except Exception as mask_exc:
|
|
1042
1068
|
masking_result = {"error": str(mask_exc)}
|
|
1043
1069
|
mix_analysis = {
|
package/mcp_server/m4l_bridge.py
CHANGED
|
@@ -1014,6 +1014,11 @@ class M4LBridge:
|
|
|
1014
1014
|
while len(s_bytes) % 4 != 0:
|
|
1015
1015
|
s_bytes += b'\x00'
|
|
1016
1016
|
arg_data += s_bytes
|
|
1017
|
+
else:
|
|
1018
|
+
raise TypeError(
|
|
1019
|
+
"OSC argument for %s must be int, float, or str, got %s"
|
|
1020
|
+
% (address, type(arg).__name__)
|
|
1021
|
+
)
|
|
1017
1022
|
|
|
1018
1023
|
tag_bytes = type_tags.encode('ascii') + b'\x00'
|
|
1019
1024
|
while len(tag_bytes) % 4 != 0:
|
|
@@ -36,7 +36,10 @@ from .remote_commands import BRIDGE_COMMANDS, REMOTE_COMMANDS
|
|
|
36
36
|
MCP_TOOLS: frozenset[str] = frozenset({
|
|
37
37
|
"apply_automation_shape",
|
|
38
38
|
"apply_gesture_template",
|
|
39
|
+
"analyze_sample",
|
|
40
|
+
"analyze_synth_patch",
|
|
39
41
|
"analyze_mix",
|
|
42
|
+
"get_masking_report",
|
|
40
43
|
"get_master_spectrum",
|
|
41
44
|
"get_emotional_arc",
|
|
42
45
|
"get_motif_graph",
|
|
@@ -92,7 +95,10 @@ READ_ONLY_TOOLS: frozenset[str] = frozenset({
|
|
|
92
95
|
"get_cue_points",
|
|
93
96
|
"get_rack_chains",
|
|
94
97
|
"get_clip_automation",
|
|
98
|
+
"analyze_sample",
|
|
99
|
+
"analyze_synth_patch",
|
|
95
100
|
"analyze_mix",
|
|
101
|
+
"get_masking_report",
|
|
96
102
|
"get_emotional_arc",
|
|
97
103
|
"get_motif_graph",
|
|
98
104
|
"get_session_diagnostics",
|
|
@@ -60,11 +60,26 @@ async def _apply_gesture_template(params: dict, ctx: Any = None) -> dict:
|
|
|
60
60
|
return await _call(apply_gesture_template, ctx, params)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
async def _analyze_sample(params: dict, ctx: Any = None) -> dict:
|
|
64
|
+
from ..sample_engine.tools import analyze_sample
|
|
65
|
+
return await _call(analyze_sample, ctx, params)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
async def _analyze_synth_patch(params: dict, ctx: Any = None) -> dict:
|
|
69
|
+
from ..synthesis_brain.tools import analyze_synth_patch
|
|
70
|
+
return await _call(analyze_synth_patch, ctx, params)
|
|
71
|
+
|
|
72
|
+
|
|
63
73
|
async def _analyze_mix(params: dict, ctx: Any = None) -> dict:
|
|
64
74
|
from ..mix_engine.tools import analyze_mix
|
|
65
75
|
return await _call(analyze_mix, ctx, params)
|
|
66
76
|
|
|
67
77
|
|
|
78
|
+
async def _get_masking_report(params: dict, ctx: Any = None) -> dict:
|
|
79
|
+
from ..mix_engine.tools import get_masking_report
|
|
80
|
+
return await _call(get_masking_report, ctx, params)
|
|
81
|
+
|
|
82
|
+
|
|
68
83
|
async def _get_master_spectrum(params: dict, ctx: Any = None) -> dict:
|
|
69
84
|
from ..tools.analyzer import get_master_spectrum
|
|
70
85
|
return await _call(get_master_spectrum, ctx, params)
|
|
@@ -151,7 +166,10 @@ def build_mcp_dispatch_registry() -> dict[str, Callable]:
|
|
|
151
166
|
"load_sample_to_simpler": _load_sample_to_simpler,
|
|
152
167
|
"apply_automation_shape": _apply_automation_shape,
|
|
153
168
|
"apply_gesture_template": _apply_gesture_template,
|
|
169
|
+
"analyze_sample": _analyze_sample,
|
|
170
|
+
"analyze_synth_patch": _analyze_synth_patch,
|
|
154
171
|
"analyze_mix": _analyze_mix,
|
|
172
|
+
"get_masking_report": _get_masking_report,
|
|
155
173
|
"get_master_spectrum": _get_master_spectrum,
|
|
156
174
|
"get_emotional_arc": _get_emotional_arc,
|
|
157
175
|
"get_motif_graph": _get_motif_graph,
|
|
@@ -83,6 +83,8 @@ REMOTE_COMMANDS: frozenset[str] = frozenset({
|
|
|
83
83
|
"capture_midi", "start_recording", "stop_recording",
|
|
84
84
|
"get_cue_points", "jump_to_cue", "toggle_cue_point",
|
|
85
85
|
"back_to_arranger", "force_arrangement",
|
|
86
|
+
"arrangement_automation_via_session_record_start",
|
|
87
|
+
"arrangement_automation_via_session_record_complete",
|
|
86
88
|
# scales — Song + per-clip scale awareness (Live 12.0+)
|
|
87
89
|
"get_song_scale", "set_song_scale", "set_song_scale_mode",
|
|
88
90
|
"list_available_scales",
|
package/mcp_server/server.py
CHANGED
|
@@ -355,14 +355,14 @@ def _coerce_schema_property(prop: dict) -> None:
|
|
|
355
355
|
def _get_all_tools():
|
|
356
356
|
"""Get all registered tools — defends against FastMCP internal drift.
|
|
357
357
|
|
|
358
|
-
FastMCP's public API doesn't expose the registry as of 3.
|
|
358
|
+
FastMCP's public API doesn't expose the registry as of 3.3.x (see
|
|
359
359
|
docs/FASTMCP_UPSTREAM_FR.md). Until it does, we probe known internal
|
|
360
360
|
attribute paths. Each probe fires in try/except so a structural
|
|
361
|
-
rearrangement (e.g. ``_components`` renamed under 3.
|
|
361
|
+
rearrangement (e.g. ``_components`` renamed under 3.4+) falls through
|
|
362
362
|
to the next path rather than exploding.
|
|
363
363
|
|
|
364
364
|
WARNING: Accesses FastMCP private internals. Pinned to
|
|
365
|
-
fastmcp>=3.
|
|
365
|
+
fastmcp>=3.3.1,<3.4.0 in requirements.txt. The startup self-test
|
|
366
366
|
(_assert_tool_registry_accessible) will fail loudly if every probe
|
|
367
367
|
returns empty — better than silently returning [] and disabling
|
|
368
368
|
schema coercion.
|
|
@@ -370,14 +370,18 @@ def _get_all_tools():
|
|
|
370
370
|
probes = [
|
|
371
371
|
# FastMCP 0.x: mcp._tool_manager._tools (dict of name -> Tool)
|
|
372
372
|
("_tool_manager._tools", lambda: list(mcp._tool_manager._tools.values())),
|
|
373
|
-
# FastMCP 3.0–3.
|
|
373
|
+
# FastMCP 3.0–3.3: mcp._local_provider._components
|
|
374
|
+
# (verified 2026-05-21 against fastmcp 3.3.1 — still the active path)
|
|
374
375
|
(
|
|
375
376
|
"_local_provider._components",
|
|
376
377
|
lambda: list(mcp._local_provider._components.values()),
|
|
377
378
|
),
|
|
378
|
-
# FastMCP 3.
|
|
379
|
-
# rename based on naming conventions in other providers).
|
|
380
|
-
#
|
|
379
|
+
# FastMCP 3.4+ speculative: mcp._local_provider._tools (anticipated
|
|
380
|
+
# rename based on naming conventions in other providers). Verified
|
|
381
|
+
# 2026-05-21 against fastmcp 3.3.1 — the rename did NOT happen in
|
|
382
|
+
# 3.3.x; ``_local_provider._components`` remains the live registry.
|
|
383
|
+
# Kept here so a future bump that DOES rename surfaces a partial
|
|
384
|
+
# match rather than a full miss.
|
|
381
385
|
(
|
|
382
386
|
"_local_provider._tools",
|
|
383
387
|
lambda: list(mcp._local_provider._tools.values()),
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livepilot",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"mcpName": "io.github.dreamrec/livepilot",
|
|
5
|
-
"description": "Agentic production system for Ableton Live 12
|
|
5
|
+
"description": "Agentic production system for Ableton Live 12 — 465 tools, 56 domains, 44 semantic moves. Device atlas (5264 devices, 120 enriched, 7 indexes), Splice intelligence (gRPC + GraphQL describe-a-sound + preview + collections + presets), 9-band spectral perception auto-loaded via ensure_analyzer_on_master, Creative Director skill, technique memory, 12 creative intelligence engines",
|
|
6
6
|
"author": "Pilot Studio",
|
|
7
7
|
"license": "BSL-1.1",
|
|
8
8
|
"type": "commonjs",
|
|
9
9
|
"bin": {
|
|
10
|
-
"livepilot": "
|
|
10
|
+
"livepilot": "bin/livepilot.js"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/dreamrec/LivePilot"
|
|
14
|
+
"url": "git+https://github.com/dreamrec/LivePilot.git"
|
|
15
15
|
},
|
|
16
16
|
"homepage": "https://github.com/dreamrec/LivePilot",
|
|
17
17
|
"bugs": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"files": [
|
|
48
48
|
"bin/**/*.js",
|
|
49
49
|
"installer/**/*.js",
|
|
50
|
+
"livepilot/**",
|
|
50
51
|
"mcp_server/**/*.py",
|
|
51
52
|
"mcp_server/**/*.json",
|
|
52
53
|
"mcp_server/**/*.yaml",
|
|
@@ -56,6 +57,9 @@
|
|
|
56
57
|
"m4l_device/LivePilot_Analyzer.amxd",
|
|
57
58
|
"m4l_device/LivePilot_Analyzer.adv",
|
|
58
59
|
"m4l_device/livepilot_bridge.js",
|
|
60
|
+
"m4l_device/LivePilot_Elektron.amxd",
|
|
61
|
+
"m4l_device/LivePilot_Elektron.maxpat",
|
|
62
|
+
"m4l_device/livepilot_elektron_bridge.js",
|
|
59
63
|
"m4l_device/BUILD_GUIDE.md",
|
|
60
64
|
"requirements.txt",
|
|
61
65
|
"README.md",
|
|
@@ -64,6 +68,17 @@
|
|
|
64
68
|
"server.json",
|
|
65
69
|
"!**/__pycache__/**",
|
|
66
70
|
"!**/*.pyc",
|
|
67
|
-
"!**/.DS_Store"
|
|
71
|
+
"!**/.DS_Store",
|
|
72
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/synths-m4l.md",
|
|
73
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/plugins-synths.md",
|
|
74
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/utility-and-workflow.md",
|
|
75
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/samples-and-irs.md",
|
|
76
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/presets-by-vibe.md",
|
|
77
|
+
"!livepilot/skills/livepilot-devices/references/m4l-vendor/**",
|
|
78
|
+
"!livepilot/skills/livepilot-devices/references/m4l-depth-pass-findings.md",
|
|
79
|
+
"!livepilot/skills/livepilot-devices/references/m4l-depth-pass-resume.md",
|
|
80
|
+
"!livepilot/skills/livepilot-devices/references/m4l-library-deep.md",
|
|
81
|
+
"!livepilot/skills/livepilot-devices/references/m4l-master-reference.md",
|
|
82
|
+
"!livepilot/skills/livepilot-devices/references/m4l-technique-map.md"
|
|
68
83
|
]
|
|
69
84
|
}
|
|
@@ -5,7 +5,7 @@ Entry point for the ControlSurface. Ableton calls create_instance(c_instance)
|
|
|
5
5
|
when this script is selected in Preferences > Link, Tempo & MIDI.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "1.26.
|
|
8
|
+
__version__ = "1.26.1"
|
|
9
9
|
|
|
10
10
|
from _Framework.ControlSurface import ControlSurface
|
|
11
11
|
from . import router
|
|
@@ -60,6 +60,67 @@ WRITE_COMMANDS = frozenset([
|
|
|
60
60
|
"clear_clip_automation",
|
|
61
61
|
])
|
|
62
62
|
|
|
63
|
+
# Future-safe write detection. WRITE_COMMANDS remains the explicit allow-list
|
|
64
|
+
# for older handlers and readability; the prefix classifier catches newer
|
|
65
|
+
# mutating handlers so they still receive the write timeout and settle delay.
|
|
66
|
+
READ_COMMAND_PREFIXES = ("get_", "list_", "scan_")
|
|
67
|
+
READ_ONLY_COMMANDS = frozenset([
|
|
68
|
+
"ping",
|
|
69
|
+
"reload_handlers",
|
|
70
|
+
])
|
|
71
|
+
WRITE_COMMAND_PREFIXES = (
|
|
72
|
+
"add_",
|
|
73
|
+
"apply_",
|
|
74
|
+
"arrangement_automation_",
|
|
75
|
+
"assign_",
|
|
76
|
+
"back_to_",
|
|
77
|
+
"capture_",
|
|
78
|
+
"cleanup_",
|
|
79
|
+
"clear_",
|
|
80
|
+
"continue_",
|
|
81
|
+
"copy_",
|
|
82
|
+
"create_",
|
|
83
|
+
"delete_",
|
|
84
|
+
"duplicate_",
|
|
85
|
+
"find_and_load_",
|
|
86
|
+
"fire_",
|
|
87
|
+
"flatten_",
|
|
88
|
+
"force_",
|
|
89
|
+
"freeze_",
|
|
90
|
+
"import_",
|
|
91
|
+
"insert_",
|
|
92
|
+
"jump_",
|
|
93
|
+
"load_",
|
|
94
|
+
"modify_",
|
|
95
|
+
"move_",
|
|
96
|
+
"nudge_",
|
|
97
|
+
"quantize_",
|
|
98
|
+
"randomize_",
|
|
99
|
+
"recall_",
|
|
100
|
+
"remove_",
|
|
101
|
+
"replace_",
|
|
102
|
+
"reset_",
|
|
103
|
+
"set_",
|
|
104
|
+
"start_",
|
|
105
|
+
"stop_",
|
|
106
|
+
"store_",
|
|
107
|
+
"tap_",
|
|
108
|
+
"toggle_",
|
|
109
|
+
"transpose_",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def is_write_command(command_type):
|
|
114
|
+
"""Return True if a command is expected to mutate Live state."""
|
|
115
|
+
if command_type in WRITE_COMMANDS:
|
|
116
|
+
return True
|
|
117
|
+
if command_type in READ_ONLY_COMMANDS:
|
|
118
|
+
return False
|
|
119
|
+
if command_type.startswith(READ_COMMAND_PREFIXES):
|
|
120
|
+
return False
|
|
121
|
+
return command_type.startswith(WRITE_COMMAND_PREFIXES)
|
|
122
|
+
|
|
123
|
+
|
|
63
124
|
# Commands that need longer timeouts (e.g., freeze renders audio)
|
|
64
125
|
SLOW_WRITE_COMMANDS = frozenset([
|
|
65
126
|
"freeze_track",
|
|
@@ -277,7 +338,7 @@ class LivePilotServer(object):
|
|
|
277
338
|
cmd_type = command.get("type", "")
|
|
278
339
|
|
|
279
340
|
# Determine timeout based on read vs write vs slow write
|
|
280
|
-
is_write = cmd_type
|
|
341
|
+
is_write = is_write_command(cmd_type)
|
|
281
342
|
if cmd_type in SLOW_WRITE_COMMANDS:
|
|
282
343
|
timeout = 35
|
|
283
344
|
elif is_write:
|
|
@@ -343,7 +404,7 @@ class LivePilotServer(object):
|
|
|
343
404
|
return
|
|
344
405
|
|
|
345
406
|
cmd_type = command.get("type", "")
|
|
346
|
-
is_write = cmd_type
|
|
407
|
+
is_write = is_write_command(cmd_type)
|
|
347
408
|
|
|
348
409
|
try:
|
|
349
410
|
song = self._cs.song()
|
package/requirements.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LivePilot MCP Server dependencies
|
|
2
|
-
numpy>=2.4.
|
|
3
|
-
fastmcp>=3.
|
|
2
|
+
numpy>=2.4.6
|
|
3
|
+
fastmcp>=3.3.1,<3.4.0 # pinned upper bound — _get_all_tools() accesses private internals
|
|
4
4
|
midiutil>=1.2.1
|
|
5
5
|
pretty_midi>=0.2.11
|
|
6
6
|
# v1.8 Perception Layer (offline analysis)
|
|
@@ -13,7 +13,7 @@ mutagen>=1.47.0
|
|
|
13
13
|
# falls back to the SQLite sounds.db which only returns locally downloaded
|
|
14
14
|
# samples (see docs/2026-04-14-bugs-discovered.md — P0-2).
|
|
15
15
|
grpcio>=1.80.0
|
|
16
|
-
protobuf>=7.
|
|
16
|
+
protobuf>=7.35.0
|
|
17
17
|
|
|
18
18
|
# Known benign warning during install:
|
|
19
19
|
# ERROR: pip's dependency resolver does not currently take into account
|
package/server.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.dreamrec/livepilot",
|
|
4
|
-
"description": "465-tool agentic MCP production system for Ableton Live 12 \u2014
|
|
4
|
+
"description": "465-tool agentic MCP production system for Ableton Live 12 \u2014 56 domains, 44 semantic moves, device atlas (5264 devices), Splice intelligence (gRPC + GraphQL), 9-band spectral perception auto-loaded, Creative Director skill, technique memory, 12 creative engines",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/dreamrec/LivePilot",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.26.
|
|
9
|
+
"version": "1.26.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "livepilot",
|
|
14
|
-
"version": "1.26.
|
|
14
|
+
"version": "1.26.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|