livepilot 1.10.7 → 1.10.8
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 +126 -0
- package/README.md +11 -9
- package/bin/livepilot.js +146 -28
- package/installer/install.js +117 -11
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +1 -1
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/__init__.py +39 -7
- package/mcp_server/atlas/tools.py +56 -15
- package/mcp_server/composer/layer_planner.py +27 -0
- package/mcp_server/composer/prompt_parser.py +15 -6
- package/mcp_server/connection.py +11 -3
- package/mcp_server/corpus/__init__.py +14 -4
- package/mcp_server/m4l_bridge.py +48 -7
- package/mcp_server/runtime/execution_router.py +16 -2
- package/mcp_server/runtime/remote_commands.py +6 -0
- package/mcp_server/sample_engine/models.py +22 -3
- package/mcp_server/semantic_moves/__init__.py +1 -0
- package/mcp_server/semantic_moves/compiler.py +9 -1
- package/mcp_server/semantic_moves/device_creation_compilers.py +47 -0
- package/mcp_server/semantic_moves/mix_compilers.py +170 -0
- package/mcp_server/semantic_moves/mix_moves.py +1 -1
- package/mcp_server/semantic_moves/models.py +5 -0
- package/mcp_server/semantic_moves/tools.py +15 -4
- package/mcp_server/server.py +7 -3
- package/mcp_server/services/singletons.py +68 -0
- package/mcp_server/splice_client/client.py +29 -8
- package/mcp_server/tools/analyzer.py +7 -6
- package/mcp_server/tools/clips.py +1 -1
- package/mcp_server/tools/midi_io.py +10 -0
- package/mcp_server/tools/tracks.py +1 -1
- package/mcp_server/tools/transport.py +1 -1
- package/mcp_server/translation_engine/tools.py +8 -4
- package/package.json +25 -3
- package/remote_script/LivePilot/__init__.py +29 -9
- package/remote_script/LivePilot/arrangement.py +12 -2
- package/remote_script/LivePilot/browser.py +16 -6
- package/remote_script/LivePilot/devices.py +10 -5
- package/remote_script/LivePilot/notes.py +13 -2
- package/remote_script/LivePilot/server.py +51 -13
- package/remote_script/LivePilot/version_detect.py +7 -4
- package/server.json +20 -0
- package/.claude-plugin/marketplace.json +0 -21
- package/.mcp.json.disabled +0 -9
- package/.mcpbignore +0 -60
- package/AGENTS.md +0 -46
- package/BUGS.md +0 -1570
- package/CODE_OF_CONDUCT.md +0 -27
- package/CONTRIBUTING.md +0 -131
- package/SECURITY.md +0 -48
- package/livepilot/.Codex-plugin/plugin.json +0 -8
- package/livepilot/.claude-plugin/plugin.json +0 -8
- package/livepilot/agents/livepilot-producer/AGENT.md +0 -313
- package/livepilot/commands/arrange.md +0 -47
- package/livepilot/commands/beat.md +0 -77
- package/livepilot/commands/evaluate.md +0 -49
- package/livepilot/commands/memory.md +0 -22
- package/livepilot/commands/mix.md +0 -44
- package/livepilot/commands/perform.md +0 -42
- package/livepilot/commands/session.md +0 -13
- package/livepilot/commands/sounddesign.md +0 -43
- package/livepilot/skills/livepilot-arrangement/SKILL.md +0 -155
- package/livepilot/skills/livepilot-composition-engine/SKILL.md +0 -107
- package/livepilot/skills/livepilot-composition-engine/references/form-patterns.md +0 -97
- package/livepilot/skills/livepilot-composition-engine/references/transition-archetypes.md +0 -102
- package/livepilot/skills/livepilot-core/SKILL.md +0 -184
- package/livepilot/skills/livepilot-core/references/ableton-workflow-patterns.md +0 -831
- package/livepilot/skills/livepilot-core/references/automation-atlas.md +0 -272
- package/livepilot/skills/livepilot-core/references/device-atlas/00-index.md +0 -110
- package/livepilot/skills/livepilot-core/references/device-atlas/distortion-and-character.md +0 -687
- package/livepilot/skills/livepilot-core/references/device-atlas/drums-and-percussion.md +0 -753
- package/livepilot/skills/livepilot-core/references/device-atlas/dynamics-and-punch.md +0 -525
- package/livepilot/skills/livepilot-core/references/device-atlas/eq-and-filtering.md +0 -402
- package/livepilot/skills/livepilot-core/references/device-atlas/midi-tools.md +0 -963
- package/livepilot/skills/livepilot-core/references/device-atlas/movement-and-modulation.md +0 -874
- package/livepilot/skills/livepilot-core/references/device-atlas/space-and-depth.md +0 -571
- package/livepilot/skills/livepilot-core/references/device-atlas/spectral-and-weird.md +0 -714
- package/livepilot/skills/livepilot-core/references/device-atlas/synths-native.md +0 -953
- package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +0 -34
- package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +0 -204
- package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +0 -173
- package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +0 -211
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +0 -188
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +0 -162
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +0 -229
- package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +0 -243
- package/livepilot/skills/livepilot-core/references/m4l-devices.md +0 -352
- package/livepilot/skills/livepilot-core/references/memory-guide.md +0 -107
- package/livepilot/skills/livepilot-core/references/midi-recipes.md +0 -402
- package/livepilot/skills/livepilot-core/references/mixing-patterns.md +0 -578
- package/livepilot/skills/livepilot-core/references/overview.md +0 -290
- package/livepilot/skills/livepilot-core/references/sample-manipulation.md +0 -724
- package/livepilot/skills/livepilot-core/references/sound-design-deep.md +0 -140
- package/livepilot/skills/livepilot-core/references/sound-design.md +0 -393
- package/livepilot/skills/livepilot-devices/SKILL.md +0 -169
- package/livepilot/skills/livepilot-evaluation/SKILL.md +0 -156
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +0 -118
- package/livepilot/skills/livepilot-evaluation/references/evaluation-contracts.md +0 -121
- package/livepilot/skills/livepilot-evaluation/references/memory-promotion.md +0 -110
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +0 -123
- package/livepilot/skills/livepilot-mix-engine/references/mix-critics.md +0 -143
- package/livepilot/skills/livepilot-mix-engine/references/mix-moves.md +0 -105
- package/livepilot/skills/livepilot-mixing/SKILL.md +0 -157
- package/livepilot/skills/livepilot-notes/SKILL.md +0 -130
- package/livepilot/skills/livepilot-performance-engine/SKILL.md +0 -122
- package/livepilot/skills/livepilot-performance-engine/references/performance-safety.md +0 -98
- package/livepilot/skills/livepilot-release/SKILL.md +0 -130
- package/livepilot/skills/livepilot-sample-engine/SKILL.md +0 -105
- package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +0 -87
- package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +0 -51
- package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +0 -131
- package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +0 -168
- package/livepilot/skills/livepilot-sound-design-engine/references/patch-model.md +0 -119
- package/livepilot/skills/livepilot-sound-design-engine/references/sound-design-critics.md +0 -118
- package/livepilot/skills/livepilot-wonder/SKILL.md +0 -79
- package/m4l_device/LivePilot_Analyzer.amxd.pre-presentation-backup +0 -0
- package/m4l_device/LivePilot_Analyzer.maxpat +0 -2705
- package/m4l_device/LivePilot_Analyzer.maxproj +0 -53
- package/manifest.json +0 -91
- package/mcp_server/splice_client/protos/app_pb2.pyi +0 -1153
- package/scripts/generate_tool_catalog.py +0 -106
- package/scripts/sync_metadata.py +0 -349
|
@@ -287,11 +287,20 @@ def load_browser_item(song, params):
|
|
|
287
287
|
# and use the subcategory or the full fragment for matching
|
|
288
288
|
if "FileId_" in device_name:
|
|
289
289
|
# URI contains an internal file ID — name-based search won't work.
|
|
290
|
-
#
|
|
290
|
+
# We fall back to one URI walk, but with a TIGHT iteration budget:
|
|
291
|
+
# this runs synchronously on Ableton's audio/main thread, and the
|
|
292
|
+
# previous 200 000-node walk could stall audio and GUI for several
|
|
293
|
+
# seconds on large libraries (documented in CLAUDE.md).
|
|
294
|
+
#
|
|
295
|
+
# If the item isn't found inside the budget, we return a clean
|
|
296
|
+
# STATE_ERROR pointing the caller at search_browser(), which does
|
|
297
|
+
# the same walk lazily from a cached Python-side index without
|
|
298
|
+
# hogging the audio thread.
|
|
291
299
|
_iterations[0] = 0
|
|
292
|
-
DEEP_MAX =
|
|
300
|
+
DEEP_MAX = 20000 # was 200_000 — 10x reduction
|
|
301
|
+
DEEP_DEPTH_MAX = 8 # was 12 — shallower depth is usually enough
|
|
293
302
|
def find_by_uri_deep(parent, target_uri, depth=0):
|
|
294
|
-
if depth >
|
|
303
|
+
if depth > DEEP_DEPTH_MAX or _iterations[0] > DEEP_MAX:
|
|
295
304
|
return None
|
|
296
305
|
try:
|
|
297
306
|
children = list(parent.children)
|
|
@@ -326,9 +335,10 @@ def load_browser_item(song, params):
|
|
|
326
335
|
}
|
|
327
336
|
|
|
328
337
|
raise ValueError(
|
|
329
|
-
"Item '%s' not found
|
|
330
|
-
"search_browser to
|
|
331
|
-
"
|
|
338
|
+
"Item '%s' not found inside deep-scan budget (FileId URI). "
|
|
339
|
+
"Use search_browser(query=...) to locate it without stalling "
|
|
340
|
+
"Ableton's audio thread, then call load_browser_item with the "
|
|
341
|
+
"returned URI." % uri
|
|
332
342
|
)
|
|
333
343
|
|
|
334
344
|
for sep in (":", "/"):
|
|
@@ -199,17 +199,22 @@ def toggle_device(song, params):
|
|
|
199
199
|
track = get_track(song, track_index)
|
|
200
200
|
device = get_device(track, device_index)
|
|
201
201
|
|
|
202
|
-
# Find the "Device On" parameter by name
|
|
202
|
+
# Find the "Device On" parameter by name — the previous fallback
|
|
203
|
+
# blindly assumed parameters[0] was an on/off switch, which for many
|
|
204
|
+
# devices is actually "Filter Frequency", "Gain", or similar. The
|
|
205
|
+
# fallback silently mutated an arbitrary parameter while reporting
|
|
206
|
+
# is_active as if toggling had worked. Now refuse to guess.
|
|
203
207
|
on_param = None
|
|
204
208
|
for p in device.parameters:
|
|
205
209
|
if p.name == "Device On":
|
|
206
210
|
on_param = p
|
|
207
211
|
break
|
|
208
212
|
if on_param is None:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
raise ValueError(
|
|
214
|
+
"Device '%s' exposes no 'Device On' parameter and cannot be "
|
|
215
|
+
"toggled programmatically. Use delete_device or disable it "
|
|
216
|
+
"through the UI." % device.name
|
|
217
|
+
)
|
|
213
218
|
|
|
214
219
|
on_param.value = 1.0 if active else 0.0
|
|
215
220
|
return {"name": device.name, "is_active": on_param.value > 0.5}
|
|
@@ -155,12 +155,23 @@ def modify_notes(song, params):
|
|
|
155
155
|
for note in all_notes:
|
|
156
156
|
note_map[note.note_id] = note
|
|
157
157
|
|
|
158
|
+
# Two-pass: validate every note_id BEFORE mutating any notes. The previous
|
|
159
|
+
# one-pass version raised ValueError mid-loop after some notes had already
|
|
160
|
+
# been mutated in place on the C++ NoteVector — yielding a half-modified
|
|
161
|
+
# state where the caller saw an error but earlier edits silently stuck
|
|
162
|
+
# (until apply_note_modifications was called, which it never was in the
|
|
163
|
+
# error path). Fail-all or apply-all is the safer contract.
|
|
164
|
+
missing = [int(mod["note_id"]) for mod in modifications
|
|
165
|
+
if int(mod["note_id"]) not in note_map]
|
|
166
|
+
if missing:
|
|
167
|
+
raise ValueError(
|
|
168
|
+
"Note IDs not found in clip: %s. No modifications applied." % missing
|
|
169
|
+
)
|
|
170
|
+
|
|
158
171
|
# Apply modifications in-place on the original NoteVector's objects
|
|
159
172
|
modified_count = 0
|
|
160
173
|
for mod in modifications:
|
|
161
174
|
note_id = int(mod["note_id"])
|
|
162
|
-
if note_id not in note_map:
|
|
163
|
-
raise ValueError("Note ID %d not found in clip" % note_id)
|
|
164
175
|
note = note_map[note_id]
|
|
165
176
|
if "pitch" in mod:
|
|
166
177
|
note.pitch = int(mod["pitch"])
|
|
@@ -197,21 +197,45 @@ class LivePilotServer(object):
|
|
|
197
197
|
self._log("Client disconnected")
|
|
198
198
|
|
|
199
199
|
def _handle_client(self, client):
|
|
200
|
-
"""Read newline-delimited JSON from a connected client.
|
|
200
|
+
"""Read newline-delimited JSON from a connected client.
|
|
201
|
+
|
|
202
|
+
Accumulate raw bytes and only attempt UTF-8 decode on newline-framed
|
|
203
|
+
lines — the previous implementation decoded each recv chunk eagerly
|
|
204
|
+
with ``errors="replace"``, which silently corrupted JSON when a
|
|
205
|
+
multi-byte UTF-8 sequence (non-ASCII filename or rack name) straddled
|
|
206
|
+
the 4096-byte recv boundary. Trailing bytes of the split codepoint
|
|
207
|
+
were converted to U+FFFD, breaking JSON parsing.
|
|
208
|
+
"""
|
|
201
209
|
client.settimeout(1.0)
|
|
202
|
-
buf =
|
|
210
|
+
buf = bytearray()
|
|
211
|
+
MAX_BUF = 4 * 1024 * 1024 # 4 MB
|
|
203
212
|
while self._running:
|
|
204
213
|
try:
|
|
205
214
|
data = client.recv(4096)
|
|
206
215
|
if not data:
|
|
207
216
|
break
|
|
208
|
-
buf
|
|
209
|
-
if len(buf) >
|
|
217
|
+
buf.extend(data)
|
|
218
|
+
if len(buf) > MAX_BUF:
|
|
210
219
|
self._log("Client buffer overflow — disconnecting")
|
|
211
220
|
break
|
|
212
|
-
while
|
|
213
|
-
|
|
214
|
-
|
|
221
|
+
while True:
|
|
222
|
+
nl = buf.find(b"\n")
|
|
223
|
+
if nl < 0:
|
|
224
|
+
break
|
|
225
|
+
raw_line = bytes(buf[:nl])
|
|
226
|
+
del buf[: nl + 1]
|
|
227
|
+
try:
|
|
228
|
+
line = raw_line.decode("utf-8").strip()
|
|
229
|
+
except UnicodeDecodeError as exc:
|
|
230
|
+
self._send(client, {
|
|
231
|
+
"id": "unknown",
|
|
232
|
+
"ok": False,
|
|
233
|
+
"error": {
|
|
234
|
+
"code": "INVALID_PARAM",
|
|
235
|
+
"message": "Invalid UTF-8 in request: %s" % exc,
|
|
236
|
+
},
|
|
237
|
+
})
|
|
238
|
+
continue
|
|
215
239
|
if line:
|
|
216
240
|
self._process_line(client, line)
|
|
217
241
|
except socket.timeout:
|
|
@@ -253,12 +277,26 @@ class LivePilotServer(object):
|
|
|
253
277
|
try:
|
|
254
278
|
self._cs.schedule_message(0, self._process_next_command)
|
|
255
279
|
except AssertionError:
|
|
256
|
-
# ControlSurface is disconnecting — return error instead of
|
|
257
|
-
# running LOM calls on the TCP thread (which would be unsafe)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
280
|
+
# ControlSurface is disconnecting — return an error instead of
|
|
281
|
+
# running LOM calls on the TCP thread (which would be unsafe).
|
|
282
|
+
#
|
|
283
|
+
# The previous version called get_nowait() unconditionally, which
|
|
284
|
+
# would happily drain a different item if one had been enqueued
|
|
285
|
+
# concurrently (e.g. if _drain_queue had just put another). Under
|
|
286
|
+
# the current single-client model the race is theoretical, but the
|
|
287
|
+
# filtered-rebuild below is correct regardless and defends against
|
|
288
|
+
# any future multi-path enqueue.
|
|
289
|
+
remaining = []
|
|
290
|
+
while True:
|
|
291
|
+
try:
|
|
292
|
+
item = self._command_queue.get_nowait()
|
|
293
|
+
except queue.Empty:
|
|
294
|
+
break
|
|
295
|
+
# Drop only OUR own pending item; preserve anything else
|
|
296
|
+
if item[1] is not response_queue:
|
|
297
|
+
remaining.append(item)
|
|
298
|
+
for item in remaining:
|
|
299
|
+
self._command_queue.put(item)
|
|
262
300
|
self._send(client, {
|
|
263
301
|
"id": request_id,
|
|
264
302
|
"ok": False,
|
|
@@ -33,7 +33,10 @@ def get_live_version():
|
|
|
33
33
|
"""Return (major, minor, patch) of the running Live instance.
|
|
34
34
|
|
|
35
35
|
Uses Live.Application.get_application() to read version info.
|
|
36
|
-
|
|
36
|
+
Returns a conservative (12, 0, 0) fallback on detection failure BUT
|
|
37
|
+
does NOT cache the fallback — earlier versions cached any failure,
|
|
38
|
+
which pinned the whole session to the oldest capability tier even
|
|
39
|
+
after Live finished initializing. Only successful reads are cached.
|
|
37
40
|
"""
|
|
38
41
|
global _cached_version
|
|
39
42
|
if _cached_version is not None:
|
|
@@ -49,10 +52,10 @@ def get_live_version():
|
|
|
49
52
|
except AttributeError:
|
|
50
53
|
patch = 0
|
|
51
54
|
_cached_version = (int(major), int(minor), int(patch))
|
|
55
|
+
return _cached_version
|
|
52
56
|
except Exception:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return _cached_version
|
|
57
|
+
# Don't cache failures — next call may succeed once Live is fully up.
|
|
58
|
+
return (12, 0, 0)
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
def has_feature(feature_name):
|
package/server.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.dreamrec/livepilot",
|
|
4
|
+
"description": "323-tool agentic MCP production system for Ableton Live 12 — device atlas, sample engine, composer",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/dreamrec/LivePilot",
|
|
7
|
+
"source": "github"
|
|
8
|
+
},
|
|
9
|
+
"version": "1.10.8",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"identifier": "livepilot",
|
|
14
|
+
"version": "1.10.8",
|
|
15
|
+
"transport": {
|
|
16
|
+
"type": "stdio"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
-
"name": "dreamrec-LivePilot",
|
|
4
|
-
"description": "Agentic MCP production system for Ableton Live 12 — 323 tools, 45 domains",
|
|
5
|
-
"owner": {
|
|
6
|
-
"name": "dreamrec",
|
|
7
|
-
"email": "dreamrec@users.noreply.github.com"
|
|
8
|
-
},
|
|
9
|
-
"plugins": [
|
|
10
|
-
{
|
|
11
|
-
"name": "livepilot",
|
|
12
|
-
"description": "Agentic production system for Ableton Live 12 — 323 tools, 45 domains, device atlas, spectral perception, technique memory, sample intelligence, auto-composition, neo-Riemannian harmony, Euclidean rhythm, species counterpoint, MIDI I/O",
|
|
13
|
-
"version": "1.10.7",
|
|
14
|
-
"author": {
|
|
15
|
-
"name": "Pilot Studio"
|
|
16
|
-
},
|
|
17
|
-
"source": "./livepilot",
|
|
18
|
-
"category": "integration"
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|
package/.mcp.json.disabled
DELETED
package/.mcpbignore
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Development files
|
|
2
|
-
.git
|
|
3
|
-
.git-backup-full
|
|
4
|
-
.github
|
|
5
|
-
.claude
|
|
6
|
-
.playwright-mcp
|
|
7
|
-
.pytest_cache
|
|
8
|
-
.venv
|
|
9
|
-
__pycache__
|
|
10
|
-
|
|
11
|
-
# Test and CI
|
|
12
|
-
tests/
|
|
13
|
-
scripts/
|
|
14
|
-
.github/
|
|
15
|
-
|
|
16
|
-
# Build artifacts
|
|
17
|
-
*.pyc
|
|
18
|
-
.DS_Store
|
|
19
|
-
*.egg-info
|
|
20
|
-
.gitignore
|
|
21
|
-
.mcpbignore
|
|
22
|
-
package-lock.json
|
|
23
|
-
|
|
24
|
-
# Untracked Ableton presets (saved by users into m4l_device/)
|
|
25
|
-
m4l_device/*.adv
|
|
26
|
-
|
|
27
|
-
# Local .amxd backups from re-freeze / rollback sessions
|
|
28
|
-
m4l_device/*.pre-*-backup
|
|
29
|
-
|
|
30
|
-
# Credentials and tokens
|
|
31
|
-
.mcpregistry_*
|
|
32
|
-
.env
|
|
33
|
-
.npmrc
|
|
34
|
-
|
|
35
|
-
# Docs and marketing (not needed at runtime)
|
|
36
|
-
# Ship only docs/manual/, docs/assets/, docs/M4L_BRIDGE.md, docs/TOOL_REFERENCE.md
|
|
37
|
-
docs/specs/
|
|
38
|
-
docs/superpowers/
|
|
39
|
-
docs/plans/
|
|
40
|
-
docs/research/
|
|
41
|
-
docs/v2-master-spec/
|
|
42
|
-
docs/LivePilot-1.7-Perception/
|
|
43
|
-
docs/2026-*
|
|
44
|
-
docs/AGENT_OS_V1.md
|
|
45
|
-
docs/COMPOSITION_ENGINE_V1.md
|
|
46
|
-
docs/ableton-library-map.md
|
|
47
|
-
docs/patreon-content.md
|
|
48
|
-
docs/social-banner.*
|
|
49
|
-
docs/screenshots/
|
|
50
|
-
|
|
51
|
-
# Large binary already in User Library after install
|
|
52
|
-
# m4l_device/LivePilot_Analyzer.amxd
|
|
53
|
-
|
|
54
|
-
# Dev config (root-level only — keep livepilot/.mcp.json which the plugin needs)
|
|
55
|
-
/.mcp.json
|
|
56
|
-
.npmignore
|
|
57
|
-
.editorconfig
|
|
58
|
-
CODE_OF_CONDUCT.md
|
|
59
|
-
CONTRIBUTING.md
|
|
60
|
-
SECURITY.md
|
package/AGENTS.md
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# LivePilot v1.10.7 — Ableton Live 12
|
|
2
|
-
|
|
3
|
-
## Project
|
|
4
|
-
- **Repo:** This directory (LivePilot)
|
|
5
|
-
- **Type:** Agentic MCP production system for Ableton Live 12
|
|
6
|
-
- **Three layers:** Device Atlas (knowledge) + M4L Analyzer (perception) + Technique Memory (learning)
|
|
7
|
-
- **Sister projects:** TDPilot (TouchDesigner), ComfyPilot (ComfyUI)
|
|
8
|
-
- **Design spec:** `docs/specs/2026-03-17-livepilot-design.md`
|
|
9
|
-
|
|
10
|
-
## Architecture
|
|
11
|
-
- **Remote Script** (`remote_script/LivePilot/`): Runs inside Ableton's Python, ControlSurface base class, TCP socket on port 9878
|
|
12
|
-
- **MCP Server** (`mcp_server/`): Python FastMCP server, validates inputs, sends commands to Remote Script
|
|
13
|
-
- **M4L Bridge** (`m4l_device/`): Max for Live Audio Effect on master track, UDP/OSC bridge for deep LOM access
|
|
14
|
-
- UDP 9880: M4L -> Server (spectral data, responses)
|
|
15
|
-
- OSC 9881: Server -> M4L (commands)
|
|
16
|
-
- `livepilot_bridge.js`: 22 bridge commands for LiveAPI access
|
|
17
|
-
- `SpectralCache`: thread-safe, time-expiring data cache (5s max age)
|
|
18
|
-
- Bridge is optional — all core tools work without it
|
|
19
|
-
- **Plugin** (`livepilot/`): Codex plugin (marketplace-compatible: `.Codex-plugin/plugin.json`)
|
|
20
|
-
- **Installer** (`installer/`): Auto-detects Ableton path, copies Remote Script
|
|
21
|
-
|
|
22
|
-
## Key Rules
|
|
23
|
-
- ALL Live Object Model (LOM) calls must execute on Ableton's main thread via schedule_message queue
|
|
24
|
-
- Live 12 minimum — use modern note API (add_new_notes, get_notes_extended, apply_note_modifications)
|
|
25
|
-
- 323 tools across 45 domains: transport, tracks, clips, notes, devices, scenes, mixing, browser, arrangement, memory, analyzer, automation, theory, generative, harmony, midi_io, perception, agent_os, composition, motif, research, planner, project_brain, runtime, evaluation, mix_engine, sound_design, transition_engine, reference_engine, translation_engine, performance_engine, song_brain, preview_studio, hook_hunter, stuckness_detector, wonder_mode, session_continuity, creative_constraints, device_forge, sample_engine, atlas, composer, experiment, musical_intelligence, semantic_moves
|
|
26
|
-
- JSON over TCP, newline-delimited, port 9878
|
|
27
|
-
- Structured errors with codes: INDEX_ERROR, NOT_FOUND, INVALID_PARAM, STATE_ERROR, TIMEOUT, INTERNAL
|
|
28
|
-
|
|
29
|
-
## M4L Bridge Notes
|
|
30
|
-
- OSC addresses must be sent WITHOUT leading `/` — Max `udpreceive` passes `/` as part of messagename
|
|
31
|
-
- `str_for_value` requires `call()` not `get()` (it's a function)
|
|
32
|
-
- `get()` in Max JS LiveAPI always returns arrays
|
|
33
|
-
- `warp_markers` is a dict property returning JSON string — use `JSON.parse()`
|
|
34
|
-
- `SimplerDevice.slices` lives on the `sample` child, not the device
|
|
35
|
-
- `replace_sample` only works on Simplers with existing samples
|
|
36
|
-
- Max freezes JS from search path cache, not source directory — copy to `~/Documents/Max 8/`
|
|
37
|
-
|
|
38
|
-
## Binary Patching Workflow (.amxd)
|
|
39
|
-
When modifying .amxd attributes that Max editor won't persist (e.g., `openinpresentation`):
|
|
40
|
-
1. Find the byte sequence in the .amxd binary
|
|
41
|
-
2. Replace with same-byte-count alternative (file size must not change)
|
|
42
|
-
3. Test by loading in Ableton
|
|
43
|
-
4. Structure: 24-byte `ampf` header + `ptch` chunk + `mx@c` header + JSON patcher + frozen deps
|
|
44
|
-
|
|
45
|
-
## Tool Count
|
|
46
|
-
Currently 323 tools. If adding/removing tools, update: README.md, package.json description, livepilot/.Codex-plugin/plugin.json, livepilot/.claude-plugin/plugin.json, server.json, livepilot/skills/livepilot-core/SKILL.md, livepilot/skills/livepilot-core/references/overview.md, AGENTS.md, CLAUDE.md, CHANGELOG.md, tests/test_tools_contract.py, docs/manual/index.md, docs/manual/tool-reference.md
|