livepilot 1.9.14 → 1.9.16
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/.claude-plugin/marketplace.json +3 -3
- package/AGENTS.md +3 -3
- package/CHANGELOG.md +82 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +8 -8
- package/livepilot/.Codex-plugin/plugin.json +2 -2
- package/livepilot/.claude-plugin/plugin.json +2 -2
- package/livepilot/agents/livepilot-producer/AGENT.md +243 -49
- package/livepilot/skills/livepilot-core/SKILL.md +81 -6
- package/livepilot/skills/livepilot-core/references/m4l-devices.md +2 -2
- package/livepilot/skills/livepilot-core/references/overview.md +3 -3
- package/livepilot/skills/livepilot-core/references/sound-design.md +3 -2
- package/livepilot/skills/livepilot-release/SKILL.md +13 -13
- package/m4l_device/livepilot_bridge.js +32 -15
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/connection.py +24 -2
- package/mcp_server/curves.py +14 -6
- package/mcp_server/evaluation/__init__.py +1 -0
- package/mcp_server/evaluation/fabric.py +575 -0
- package/mcp_server/evaluation/feature_extractors.py +84 -0
- package/mcp_server/evaluation/policy.py +67 -0
- package/mcp_server/evaluation/tools.py +53 -0
- package/mcp_server/m4l_bridge.py +9 -1
- package/mcp_server/memory/__init__.py +11 -2
- package/mcp_server/memory/anti_memory.py +78 -0
- package/mcp_server/memory/promotion.py +94 -0
- package/mcp_server/memory/session_memory.py +108 -0
- package/mcp_server/memory/taste_memory.py +158 -0
- package/mcp_server/memory/technique_store.py +27 -18
- package/mcp_server/memory/tools.py +112 -0
- package/mcp_server/mix_engine/__init__.py +1 -0
- package/mcp_server/mix_engine/critics.py +299 -0
- package/mcp_server/mix_engine/models.py +152 -0
- package/mcp_server/mix_engine/planner.py +103 -0
- package/mcp_server/mix_engine/state_builder.py +316 -0
- package/mcp_server/mix_engine/tools.py +220 -0
- package/mcp_server/performance_engine/__init__.py +1 -0
- package/mcp_server/performance_engine/models.py +148 -0
- package/mcp_server/performance_engine/planner.py +267 -0
- package/mcp_server/performance_engine/safety.py +165 -0
- package/mcp_server/performance_engine/tools.py +183 -0
- package/mcp_server/project_brain/__init__.py +6 -0
- package/mcp_server/project_brain/arrangement_graph.py +64 -0
- package/mcp_server/project_brain/automation_graph.py +72 -0
- package/mcp_server/project_brain/builder.py +123 -0
- package/mcp_server/project_brain/capability_graph.py +64 -0
- package/mcp_server/project_brain/models.py +282 -0
- package/mcp_server/project_brain/refresh.py +86 -0
- package/mcp_server/project_brain/role_graph.py +103 -0
- package/mcp_server/project_brain/session_graph.py +51 -0
- package/mcp_server/project_brain/tools.py +144 -0
- package/mcp_server/reference_engine/__init__.py +1 -0
- package/mcp_server/reference_engine/gap_analyzer.py +239 -0
- package/mcp_server/reference_engine/models.py +105 -0
- package/mcp_server/reference_engine/profile_builder.py +149 -0
- package/mcp_server/reference_engine/tactic_router.py +117 -0
- package/mcp_server/reference_engine/tools.py +236 -0
- package/mcp_server/runtime/__init__.py +1 -0
- package/mcp_server/runtime/action_ledger.py +117 -0
- package/mcp_server/runtime/action_ledger_models.py +91 -0
- package/mcp_server/runtime/action_tools.py +57 -0
- package/mcp_server/runtime/capability_state.py +219 -0
- package/mcp_server/runtime/safety_kernel.py +339 -0
- package/mcp_server/runtime/safety_tools.py +42 -0
- package/mcp_server/runtime/tools.py +67 -0
- package/mcp_server/server.py +17 -0
- package/mcp_server/sound_design/__init__.py +1 -0
- package/mcp_server/sound_design/critics.py +297 -0
- package/mcp_server/sound_design/models.py +147 -0
- package/mcp_server/sound_design/planner.py +104 -0
- package/mcp_server/sound_design/tools.py +297 -0
- package/mcp_server/tools/_agent_os_engine.py +947 -0
- package/mcp_server/tools/_composition_engine.py +1530 -0
- package/mcp_server/tools/_conductor.py +199 -0
- package/mcp_server/tools/_conductor_budgets.py +222 -0
- package/mcp_server/tools/_evaluation_contracts.py +91 -0
- package/mcp_server/tools/_form_engine.py +416 -0
- package/mcp_server/tools/_motif_engine.py +351 -0
- package/mcp_server/tools/_planner_engine.py +516 -0
- package/mcp_server/tools/_research_engine.py +542 -0
- package/mcp_server/tools/_research_provider.py +185 -0
- package/mcp_server/tools/_snapshot_normalizer.py +49 -0
- package/mcp_server/tools/agent_os.py +448 -0
- package/mcp_server/tools/analyzer.py +18 -0
- package/mcp_server/tools/automation.py +25 -10
- package/mcp_server/tools/composition.py +645 -0
- package/mcp_server/tools/devices.py +15 -1
- package/mcp_server/tools/midi_io.py +3 -1
- package/mcp_server/tools/motif.py +104 -0
- package/mcp_server/tools/planner.py +144 -0
- package/mcp_server/tools/research.py +223 -0
- package/mcp_server/tools/tracks.py +21 -6
- package/mcp_server/tools/transport.py +10 -2
- package/mcp_server/transition_engine/__init__.py +6 -0
- package/mcp_server/transition_engine/archetypes.py +167 -0
- package/mcp_server/transition_engine/critics.py +340 -0
- package/mcp_server/transition_engine/models.py +90 -0
- package/mcp_server/transition_engine/tools.py +291 -0
- package/mcp_server/translation_engine/__init__.py +5 -0
- package/mcp_server/translation_engine/critics.py +297 -0
- package/mcp_server/translation_engine/models.py +27 -0
- package/mcp_server/translation_engine/tools.py +108 -0
- package/package.json +2 -2
- package/remote_script/LivePilot/__init__.py +1 -1
- package/remote_script/LivePilot/arrangement.py +21 -3
- package/remote_script/LivePilot/clips.py +22 -6
- package/remote_script/LivePilot/notes.py +9 -1
- package/remote_script/LivePilot/server.py +6 -6
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: livepilot-core
|
|
3
|
-
description: Core discipline for LivePilot — agentic production system for Ableton Live 12.
|
|
3
|
+
description: Core discipline for LivePilot — agentic production system for Ableton Live 12. 236 tools across 32 domains. Device atlas (280+ devices), M4L analyzer (spectrum/RMS/key detection), technique memory, automation intelligence (16 curve types, 15 recipes), music theory (Krumhansl-Schmuckler, species counterpoint), generative algorithms (Euclidean rhythm, tintinnabuli, phase shift), neo-Riemannian harmony (PRL transforms, Tonnetz), MIDI file I/O. Use whenever working with Ableton Live through MCP tools.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# LivePilot Core — Ableton Live 12
|
|
7
7
|
|
|
8
|
-
Agentic production system for Ableton Live 12.
|
|
8
|
+
Agentic production system for Ableton Live 12. 236 tools across 32 domains, three layers:
|
|
9
9
|
|
|
10
10
|
- **Device Atlas** — A structured knowledge corpus of 280+ instruments, 139 drum kits, and 350+ impulse responses. Consult the atlas before loading any device. It contains real browser URIs, preset names, and sonic descriptions. Never guess a device name — look it up.
|
|
11
11
|
- **M4L Analyzer** — Real-time audio analysis on the master bus (8-band spectrum, RMS/peak, key detection). Use it to verify mixing decisions, detect frequency problems, and find the key before writing harmonic content.
|
|
12
12
|
- **Technique Memory** — Persistent storage for production decisions. Consult `memory_recall` before creative tasks to understand the user's taste. Save techniques when the user likes something. The memory shapes future decisions without constraining them.
|
|
13
13
|
|
|
14
|
-
These layers sit on top of
|
|
14
|
+
These layers sit on top of 236 deterministic tools across 32 domains: transport, tracks, clips, notes, devices, scenes, mixing, browser, arrangement, memory, analyzer, automation, theory, generative, harmony, MIDI I/O, perception, agent_os, composition, motif, research, planner, project_brain, runtime, evaluation, memory_fabric, mix_engine, sound_design, transition_engine, reference_engine, translation_engine, and performance_engine.
|
|
15
15
|
|
|
16
16
|
## Golden Rules
|
|
17
17
|
|
|
@@ -35,7 +35,7 @@ These layers sit on top of 178 deterministic tools across 17 domains: transport,
|
|
|
35
35
|
Not all tools respond instantly. Know the tiers and act accordingly.
|
|
36
36
|
|
|
37
37
|
### Instant (<1s) — Use freely, no warning needed
|
|
38
|
-
All
|
|
38
|
+
All 236 core tools (transport, tracks, clips, notes, devices, scenes, mixing, browser, arrangement, memory, automation, theory, generative, harmony, midi_io, perception) plus Layer A perception tools (spectral shape, timbral profile, mel spectrum, chroma, onsets, harmonic/percussive, novelty, momentary loudness). These are the reflex tools — call them anytime without hesitation.
|
|
39
39
|
|
|
40
40
|
### Fast (1-5s) — Use freely, barely noticeable
|
|
41
41
|
`analyze_loudness` · `analyze_dynamic_range` · `compare_loudness`
|
|
@@ -133,7 +133,7 @@ Never skip levels. The user's question determines the entry point, but always st
|
|
|
133
133
|
- **Dead AU/VST plugin** — `parameter_count` <= 1 on a PluginDevice (plugin shell loaded, DSP engine crashed)
|
|
134
134
|
- **Sample-dependent plugin with no sample** — granular synths, bare samplers, and sample players load "successfully" with many parameters but produce zero audio without source material. The sneakiest silent failure because `get_device_info` looks healthy.
|
|
135
135
|
|
|
136
|
-
## Tool Domains (
|
|
136
|
+
## Tool Domains (236 total)
|
|
137
137
|
|
|
138
138
|
### Transport (12)
|
|
139
139
|
`get_session_info` · `set_tempo` · `set_time_signature` · `start_playback` · `stop_playback` · `continue_playback` · `toggle_metronome` · `set_session_loop` · `undo` · `redo` · `get_recent_actions` · `get_session_diagnostics`
|
|
@@ -249,6 +249,81 @@ MIDI file import/export — works with standard .mid files on disk.
|
|
|
249
249
|
- `extract_piano_roll` returns a 2D velocity matrix (pitch × time) from a .mid file for visualization or processing
|
|
250
250
|
- Dependencies: midiutil (export), pretty-midi (import/analysis) — lazy-loaded, ~5 MB total
|
|
251
251
|
|
|
252
|
+
### Agent OS (8)
|
|
253
|
+
Goal-driven decision loop — compile goals, build world models, evaluate moves, learn from outcomes.
|
|
254
|
+
|
|
255
|
+
**Tools:** `compile_goal_vector` · `build_world_model` · `evaluate_move` · `analyze_outcomes` · `get_technique_card` · `get_taste_profile` · `get_turn_budget` · `route_request`
|
|
256
|
+
|
|
257
|
+
### Composition (9)
|
|
258
|
+
Large-scale arrangement structure — sections, phrases, gestures, harmonic fields, transitions.
|
|
259
|
+
|
|
260
|
+
**Tools:** `analyze_composition` · `get_section_graph` · `get_phrase_grid` · `plan_gesture` · `evaluate_composition_move` · `get_harmony_field` · `get_transition_analysis` · `apply_gesture_template` · `get_section_outcomes`
|
|
261
|
+
|
|
262
|
+
### Motif (2)
|
|
263
|
+
Recurring pattern detection and classical transformation.
|
|
264
|
+
|
|
265
|
+
**Tools:** `get_motif_graph` · `transform_motif`
|
|
266
|
+
|
|
267
|
+
### Research (3)
|
|
268
|
+
Production technique lookup, emotional arc analysis, and genre-specific tactics.
|
|
269
|
+
|
|
270
|
+
**Tools:** `research_technique` · `get_emotional_arc` · `get_style_tactics`
|
|
271
|
+
|
|
272
|
+
### Planner (2)
|
|
273
|
+
Arrangement planning — transform loops into full structures.
|
|
274
|
+
|
|
275
|
+
**Tools:** `plan_arrangement` · `transform_section`
|
|
276
|
+
|
|
277
|
+
### Project Brain (2)
|
|
278
|
+
Comprehensive project model — tracks, sections, capabilities, staleness.
|
|
279
|
+
|
|
280
|
+
**Tools:** `build_project_brain` · `get_project_brain_summary`
|
|
281
|
+
|
|
282
|
+
### Runtime (4)
|
|
283
|
+
Capability state, action ledger, and safety validation.
|
|
284
|
+
|
|
285
|
+
**Tools:** `get_capability_state` · `get_action_ledger_summary` · `get_last_move` · `check_safety`
|
|
286
|
+
|
|
287
|
+
### Evaluation (1)
|
|
288
|
+
Unified move evaluation using the Evaluation Fabric.
|
|
289
|
+
|
|
290
|
+
**Tools:** `evaluate_with_fabric`
|
|
291
|
+
|
|
292
|
+
### Memory Fabric (6)
|
|
293
|
+
Anti-preferences, session memory, taste dimensions, and promotion candidates.
|
|
294
|
+
|
|
295
|
+
**Tools:** `get_anti_preferences` · `record_anti_preference` · `get_promotion_candidates` · `get_session_memory` · `add_session_memory` · `get_taste_dimensions`
|
|
296
|
+
|
|
297
|
+
### Mix Engine (6)
|
|
298
|
+
Spectral mix analysis, issue detection, move planning, and evaluation.
|
|
299
|
+
|
|
300
|
+
**Tools:** `analyze_mix` · `get_mix_issues` · `plan_mix_move` · `evaluate_mix_move` · `get_masking_report` · `get_mix_summary`
|
|
301
|
+
|
|
302
|
+
### Sound Design (4)
|
|
303
|
+
Device chain analysis, issue detection, and move planning per track.
|
|
304
|
+
|
|
305
|
+
**Tools:** `analyze_sound_design` · `get_sound_design_issues` · `plan_sound_design_move` · `get_patch_model`
|
|
306
|
+
|
|
307
|
+
### Transition Engine (3)
|
|
308
|
+
Section transition analysis, planning, and scoring.
|
|
309
|
+
|
|
310
|
+
**Tools:** `analyze_transition` · `plan_transition` · `score_transition`
|
|
311
|
+
|
|
312
|
+
### Reference Engine (3)
|
|
313
|
+
Reference profile building, gap analysis, and move planning.
|
|
314
|
+
|
|
315
|
+
**Tools:** `build_reference_profile` · `analyze_reference_gaps` · `plan_reference_moves`
|
|
316
|
+
|
|
317
|
+
### Translation Engine (2)
|
|
318
|
+
Playback robustness — mono safety, small speakers, harshness detection.
|
|
319
|
+
|
|
320
|
+
**Tools:** `check_translation` · `get_translation_issues`
|
|
321
|
+
|
|
322
|
+
### Performance Engine (3)
|
|
323
|
+
Live performance support — scene state, safe moves, and handoffs.
|
|
324
|
+
|
|
325
|
+
**Tools:** `get_performance_state` · `get_performance_safe_moves` · `plan_scene_handoff`
|
|
326
|
+
|
|
252
327
|
## Workflow: Building a Beat
|
|
253
328
|
|
|
254
329
|
1. `get_session_info` — check current state
|
|
@@ -397,7 +472,7 @@ Deep production knowledge lives in `references/`. Consult these when making crea
|
|
|
397
472
|
|
|
398
473
|
| File | What's inside | When to consult |
|
|
399
474
|
|------|--------------|-----------------|
|
|
400
|
-
| `references/overview.md` | All
|
|
475
|
+
| `references/overview.md` | All 236 tools mapped with params, units, ranges | Quick lookup for any tool |
|
|
401
476
|
| `references/midi-recipes.md` | Drum patterns by genre, chord voicings, scales, hi-hat techniques, humanization, polymetrics | Programming MIDI notes, building beats |
|
|
402
477
|
| `references/sound-design.md` | Stock instruments/effects, parameter recipes for bass/pad/lead/pluck, device chain patterns | Loading and configuring devices |
|
|
403
478
|
| `references/mixing-patterns.md` | Gain staging, parallel compression, sidechain, EQ by instrument, bus processing, stereo width | Setting volumes, panning, adding effects |
|
|
@@ -32,7 +32,7 @@ Ableton's browser is the source for all devices, presets, and samples. The `sear
|
|
|
32
32
|
| **Delay** | Delay, Echo, Grain Delay, Beat Repeat, Spectral Time |
|
|
33
33
|
| **Reverb** | Reverb, Convolution Reverb (M4L), Hybrid Reverb |
|
|
34
34
|
| **Distortion** | Saturator, Overdrive, Erosion, Redux, Pedal, Amp, Cabinet |
|
|
35
|
-
| **Modulation** | Chorus-Ensemble, Phaser-Flanger,
|
|
35
|
+
| **Modulation** | Chorus-Ensemble, Phaser-Flanger, Shifter, Ring Mod |
|
|
36
36
|
| **Utility** | Utility, Tuner, Spectrum, External Audio Effect |
|
|
37
37
|
| **Spatial** | Surround Panner (if available) |
|
|
38
38
|
|
|
@@ -295,7 +295,7 @@ find_and_load_device(track_index=0, name="Arpeggiator")
|
|
|
295
295
|
| Delay | `Delay`, `Echo`, `Grain Delay`, `Beat Repeat` |
|
|
296
296
|
| Reverb | `Reverb`, `Hybrid Reverb` |
|
|
297
297
|
| Distortion | `Saturator`, `Overdrive`, `Erosion`, `Redux`, `Pedal`, `Amp`, `Cabinet` |
|
|
298
|
-
| Modulation | `Chorus-Ensemble`, `Phaser-Flanger`, `
|
|
298
|
+
| Modulation | `Chorus-Ensemble`, `Phaser-Flanger`, `Shifter` |
|
|
299
299
|
| Utility | `Utility`, `Tuner`, `Spectrum` |
|
|
300
300
|
| MIDI FX | `Arpeggiator`, `Chord`, `Note Length`, `Pitch`, `Random`, `Scale`, `Velocity`, `CC Control` |
|
|
301
301
|
| Racks | `Instrument Rack`, `Audio Effect Rack`, `MIDI Effect Rack` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# LivePilot v1.9.
|
|
1
|
+
# LivePilot v1.9.16 — Architecture & Tool Reference
|
|
2
2
|
|
|
3
|
-
Agentic production system for Ableton Live 12.
|
|
3
|
+
Agentic production system for Ableton Live 12. 236 tools across 32 domains. Device atlas (280+ devices), spectral perception (M4L analyzer), technique memory, automation intelligence (16 curve types, 15 recipes), music theory (Krumhansl-Schmuckler, species counterpoint), generative algorithms (Euclidean rhythm, tintinnabuli, phase shift, additive process), neo-Riemannian harmony (PRL transforms, Tonnetz), MIDI file I/O.
|
|
4
4
|
|
|
5
5
|
## Architecture
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ A flat tool list lets the AI press buttons. LivePilot's three layers give it con
|
|
|
32
32
|
|
|
33
33
|
This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spectrum to confirm the mud is actually reduced."
|
|
34
34
|
|
|
35
|
-
## The
|
|
35
|
+
## The 236 Tools — What Each One Does
|
|
36
36
|
|
|
37
37
|
### Transport (12) — Playback, tempo, global state, diagnostics
|
|
38
38
|
|
|
@@ -215,11 +215,12 @@ Simple 3-band EQ for quick tonal shaping.
|
|
|
215
215
|
- `Feedback` — Intensity/resonance
|
|
216
216
|
- **Phaser**: Sweeping notches. **Flanger**: Jet/whoosh effect.
|
|
217
217
|
|
|
218
|
-
**Frequency Shifter
|
|
218
|
+
**Shifter** (renamed from Frequency Shifter in Live 12)
|
|
219
219
|
- `Frequency` — Shift amount in Hz (not semitones — inharmonic)
|
|
220
220
|
- `Drive` — Input gain
|
|
221
221
|
- `Dry/Wet` — Mix
|
|
222
222
|
- **Use for**: Metallic textures, detuned unease, ring-mod effects
|
|
223
|
+
- **Browser name**: `Shifter` (use this with `find_and_load_device`)
|
|
223
224
|
|
|
224
225
|
### Utility
|
|
225
226
|
|
|
@@ -320,7 +321,7 @@ LFO: Multiple slow LFOs mapped to position, filter, pitch (subtle)
|
|
|
320
321
|
```
|
|
321
322
|
- Heavy Reverb (5-10s decay, high diffusion, 80-100% wet)
|
|
322
323
|
- Delay with high feedback (60-80%), filtered
|
|
323
|
-
-
|
|
324
|
+
- Shifter at very small values (+/- 1-5 Hz) for movement
|
|
324
325
|
- Grain Delay for granular textures
|
|
325
326
|
|
|
326
327
|
### 808 Bass (Simpler or Drum Rack)
|
|
@@ -28,26 +28,26 @@ Run this checklist EVERY time the user says "update everything", "push", "releas
|
|
|
28
28
|
|
|
29
29
|
## 2. Tool Count (must ALL match)
|
|
30
30
|
|
|
31
|
-
Current: **
|
|
31
|
+
Current: **236 tools across 32 domains**.
|
|
32
32
|
Core (no M4L): **149**. Analyzer (M4L): **29**. Perception (offline): **4**.
|
|
33
33
|
|
|
34
34
|
Verify: `grep -rc "@mcp.tool" mcp_server/tools/ | grep -v ":0" | awk -F: '{sum+=$2} END{print sum}'`
|
|
35
35
|
|
|
36
36
|
Files that reference tool count:
|
|
37
|
-
- [ ] `README.md` — header, PERCEPTION section ("
|
|
38
|
-
- [ ] `package.json` → `"description"` (
|
|
37
|
+
- [ ] `README.md` — header, PERCEPTION section ("207 core...29 analyzer"), Analyzer table header "(29)", Perception table header "(4)"
|
|
38
|
+
- [ ] `package.json` → `"description"` (236 tools, 32 domains)
|
|
39
39
|
- [ ] `server.json` → `"description"`
|
|
40
40
|
- [ ] `livepilot/.Codex-plugin/plugin.json` → `"description"` (primary Codex manifest)
|
|
41
41
|
- [ ] `livepilot/.claude-plugin/plugin.json` → `"description"` (must match Codex plugin)
|
|
42
42
|
- [ ] `.claude-plugin/marketplace.json` → `"description"`
|
|
43
|
-
- [ ] `CLAUDE.md` → "
|
|
44
|
-
- [ ] `livepilot/skills/livepilot-core/SKILL.md` — "
|
|
45
|
-
- [ ] `livepilot/skills/livepilot-core/references/overview.md` — "
|
|
43
|
+
- [ ] `CLAUDE.md` → "236 tools across 32 domains"
|
|
44
|
+
- [ ] `livepilot/skills/livepilot-core/SKILL.md` — "236 tools across 32 domains", Analyzer (29), Perception (4)
|
|
45
|
+
- [ ] `livepilot/skills/livepilot-core/references/overview.md` — "236 tools across 32 domains"
|
|
46
46
|
- [ ] `docs/manual/index.md` — domain table: Analyzer (29), Perception (4)
|
|
47
|
-
- [ ] `docs/manual/getting-started.md` — "
|
|
47
|
+
- [ ] `docs/manual/getting-started.md` — "207 core tools...29 analyzer"
|
|
48
48
|
- [ ] `docs/manual/tool-reference.md` — all domains present with correct counts
|
|
49
49
|
- [ ] `docs/TOOL_REFERENCE.md` — all domains present
|
|
50
|
-
- [ ] `docs/M4L_BRIDGE.md` — "
|
|
50
|
+
- [ ] `docs/M4L_BRIDGE.md` — "207 core tools...29 analyzer"
|
|
51
51
|
- [ ] `docs/social-banner.html`
|
|
52
52
|
- [ ] `mcp_server/tools/analyzer.py` → module docstring
|
|
53
53
|
- [ ] `tests/test_tools_contract.py` → expected total count
|
|
@@ -56,10 +56,10 @@ Files that reference tool count:
|
|
|
56
56
|
|
|
57
57
|
## 3. Domain Count
|
|
58
58
|
|
|
59
|
-
Current: **
|
|
59
|
+
Current: **32 domains**: transport, tracks, clips, notes, devices, scenes, mixing, browser, arrangement, memory, analyzer, automation, theory, generative, harmony, midi_io, perception, agent_os, composition, research, planner, project_brain, runtime, evaluation, memory_fabric, mix_engine, sound_design, transition_engine, reference_engine, translation_engine, performance_engine.
|
|
60
60
|
|
|
61
|
-
- [ ] All files that mention domain count say "
|
|
62
|
-
- [ ] Domain lists include ALL
|
|
61
|
+
- [ ] All files that mention domain count say "32 domains"
|
|
62
|
+
- [ ] Domain lists include ALL 32 (especially newer domains — they're the most often omitted)
|
|
63
63
|
|
|
64
64
|
## 4. npm Registry
|
|
65
65
|
|
|
@@ -89,8 +89,8 @@ Current: **17 domains**: transport, tracks, clips, notes, devices, scenes, mixin
|
|
|
89
89
|
|
|
90
90
|
- [ ] `README.md` — features match current capabilities, "Coming" section is accurate
|
|
91
91
|
- [ ] `docs/manual/getting-started.md` — install instructions current
|
|
92
|
-
- [ ] `docs/manual/tool-reference.md` — all
|
|
93
|
-
- [ ] `docs/TOOL_REFERENCE.md` — all
|
|
92
|
+
- [ ] `docs/manual/tool-reference.md` — all 32 domains listed, all 236 tools present
|
|
93
|
+
- [ ] `docs/TOOL_REFERENCE.md` — all 32 domains present
|
|
94
94
|
- [ ] `docs/M4L_BRIDGE.md` — architecture accurate, core tool count correct
|
|
95
95
|
|
|
96
96
|
## 9. Derived Artifacts
|
|
@@ -84,7 +84,7 @@ function anything() {
|
|
|
84
84
|
function dispatch(cmd, args) {
|
|
85
85
|
switch(cmd) {
|
|
86
86
|
case "ping":
|
|
87
|
-
send_response({"ok": true, "version": "1.9.
|
|
87
|
+
send_response({"ok": true, "version": "1.9.16"});
|
|
88
88
|
break;
|
|
89
89
|
case "get_params":
|
|
90
90
|
cmd_get_params(args);
|
|
@@ -513,16 +513,17 @@ function cmd_get_selected() {
|
|
|
513
513
|
appointed_device: null
|
|
514
514
|
};
|
|
515
515
|
|
|
516
|
-
// Selected track
|
|
516
|
+
// Selected track — match by object ID (not name, which can be duplicated)
|
|
517
517
|
try {
|
|
518
518
|
cursor_b.goto("live_set view selected_track");
|
|
519
519
|
result.selected_track_name = cursor_b.get("name").toString();
|
|
520
|
-
|
|
520
|
+
var selected_id = cursor_b.id;
|
|
521
|
+
// Get track index by walking tracks and comparing IDs
|
|
521
522
|
cursor_a.goto("live_set");
|
|
522
523
|
var tc = cursor_a.getcount("tracks");
|
|
523
524
|
for (var i = 0; i < tc; i++) {
|
|
524
525
|
cursor_a.goto("live_set tracks " + i);
|
|
525
|
-
if (cursor_a.
|
|
526
|
+
if (cursor_a.id === selected_id) {
|
|
526
527
|
result.selected_track = i;
|
|
527
528
|
break;
|
|
528
529
|
}
|
|
@@ -533,7 +534,7 @@ function cmd_get_selected() {
|
|
|
533
534
|
var rtc = cursor_a.getcount("return_tracks");
|
|
534
535
|
for (var j = 0; j < rtc; j++) {
|
|
535
536
|
cursor_a.goto("live_set return_tracks " + j);
|
|
536
|
-
if (cursor_a.
|
|
537
|
+
if (cursor_a.id === selected_id) {
|
|
537
538
|
result.selected_track = -(j + 1); // -1, -2, ... convention
|
|
538
539
|
break;
|
|
539
540
|
}
|
|
@@ -542,7 +543,7 @@ function cmd_get_selected() {
|
|
|
542
543
|
// Check master track if still not found
|
|
543
544
|
if (result.selected_track === -1) {
|
|
544
545
|
cursor_a.goto("live_set master_track");
|
|
545
|
-
if (cursor_a.
|
|
546
|
+
if (cursor_a.id === selected_id) {
|
|
546
547
|
result.selected_track = -1000; // master convention
|
|
547
548
|
}
|
|
548
549
|
}
|
|
@@ -743,7 +744,7 @@ function base64_decode(str) {
|
|
|
743
744
|
|
|
744
745
|
function _utf8_decode(bytes) {
|
|
745
746
|
// Convert a UTF-8 byte array back to a JavaScript string.
|
|
746
|
-
// Handles BMP codepoints
|
|
747
|
+
// Handles BMP codepoints and 4-byte sequences (emoji/supplementary planes).
|
|
747
748
|
var result = "";
|
|
748
749
|
for (var i = 0; i < bytes.length;) {
|
|
749
750
|
var b0 = bytes[i];
|
|
@@ -754,17 +755,30 @@ function _utf8_decode(bytes) {
|
|
|
754
755
|
var b1 = bytes[i + 1];
|
|
755
756
|
result += String.fromCharCode(((b0 & 0x1F) << 6) | (b1 & 0x3F));
|
|
756
757
|
i += 2;
|
|
757
|
-
} else if (i + 2 < bytes.length) {
|
|
758
|
-
|
|
759
|
-
var
|
|
758
|
+
} else if ((b0 & 0xF0) === 0xE0 && i + 2 < bytes.length) {
|
|
759
|
+
// 3-byte sequence (U+0800..U+FFFF)
|
|
760
|
+
var b1_3 = bytes[i + 1];
|
|
761
|
+
var b2_3 = bytes[i + 2];
|
|
760
762
|
result += String.fromCharCode(
|
|
761
763
|
((b0 & 0x0F) << 12) |
|
|
762
|
-
((
|
|
763
|
-
(
|
|
764
|
+
((b1_3 & 0x3F) << 6) |
|
|
765
|
+
(b2_3 & 0x3F)
|
|
764
766
|
);
|
|
765
767
|
i += 3;
|
|
768
|
+
} else if ((b0 & 0xF8) === 0xF0 && i + 3 < bytes.length) {
|
|
769
|
+
// 4-byte sequence (U+10000..U+10FFFF) — emoji and supplementary planes
|
|
770
|
+
var cp = ((b0 & 0x07) << 18) |
|
|
771
|
+
((bytes[i + 1] & 0x3F) << 12) |
|
|
772
|
+
((bytes[i + 2] & 0x3F) << 6) |
|
|
773
|
+
(bytes[i + 3] & 0x3F);
|
|
774
|
+
// Encode as UTF-16 surrogate pair
|
|
775
|
+
cp -= 0x10000;
|
|
776
|
+
result += String.fromCharCode(0xD800 + (cp >> 10));
|
|
777
|
+
result += String.fromCharCode(0xDC00 + (cp & 0x3FF));
|
|
778
|
+
i += 4;
|
|
766
779
|
} else {
|
|
767
|
-
|
|
780
|
+
// Skip invalid byte
|
|
781
|
+
i += 1;
|
|
768
782
|
}
|
|
769
783
|
}
|
|
770
784
|
return result;
|
|
@@ -1311,7 +1325,9 @@ function cmd_get_plugin_params(args) {
|
|
|
1311
1325
|
var is_plugin = (class_name === "PluginDevice" || class_name === "AuPluginDevice");
|
|
1312
1326
|
if (!is_plugin) {
|
|
1313
1327
|
send_response({
|
|
1314
|
-
"error": "Device is " + class_name + ", not a plugin (PluginDevice/AuPluginDevice)"
|
|
1328
|
+
"error": "Device is " + class_name + ", not a plugin (PluginDevice/AuPluginDevice). " +
|
|
1329
|
+
"This tool only works on AU/VST plugins. Use get_device_parameters for native Ableton devices. " +
|
|
1330
|
+
"Check get_device_info().is_plugin to verify before calling."
|
|
1315
1331
|
});
|
|
1316
1332
|
return;
|
|
1317
1333
|
}
|
|
@@ -1427,7 +1443,8 @@ function cmd_get_plugin_presets(args) {
|
|
|
1427
1443
|
var is_plugin = (class_name === "PluginDevice" || class_name === "AuPluginDevice");
|
|
1428
1444
|
if (!is_plugin) {
|
|
1429
1445
|
send_response({
|
|
1430
|
-
"error": "Device is " + class_name + ", not a plugin"
|
|
1446
|
+
"error": "Device is " + class_name + ", not a plugin. " +
|
|
1447
|
+
"This tool only works on AU/VST plugins. Check get_device_info().is_plugin first."
|
|
1431
1448
|
});
|
|
1432
1449
|
return;
|
|
1433
1450
|
}
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.9.
|
|
2
|
+
__version__ = "1.9.16"
|
package/mcp_server/connection.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import json
|
|
6
7
|
import os
|
|
7
8
|
import socket
|
|
@@ -40,6 +41,8 @@ def _friendly_error(code: str, message: str, command_type: str) -> str:
|
|
|
40
41
|
"""Format an error from the Remote Script into a user-friendly message."""
|
|
41
42
|
hint = _ERROR_HINTS.get(code, "")
|
|
42
43
|
parts = [f"[{code}] {message}"]
|
|
44
|
+
if command_type:
|
|
45
|
+
parts.append(f"(while running '{command_type}')")
|
|
43
46
|
if hint:
|
|
44
47
|
parts.append(hint)
|
|
45
48
|
return " ".join(parts)
|
|
@@ -143,7 +146,9 @@ class AbletonConnection:
|
|
|
143
146
|
|
|
144
147
|
Thread-safe: a lock serializes all TCP send/receive cycles to
|
|
145
148
|
prevent socket corruption when multiple MCP tools fire concurrently.
|
|
146
|
-
Retries once on
|
|
149
|
+
Retries once on connection errors (command never reached Ableton).
|
|
150
|
+
Does NOT retry on timeouts — Ableton may have already processed the
|
|
151
|
+
command, and retrying would cause duplicate mutations.
|
|
147
152
|
"""
|
|
148
153
|
with self._lock:
|
|
149
154
|
# Ensure we have a connection
|
|
@@ -156,7 +161,15 @@ class AbletonConnection:
|
|
|
156
161
|
|
|
157
162
|
try:
|
|
158
163
|
response = self._send_raw(command)
|
|
159
|
-
except
|
|
164
|
+
except AbletonConnectionError as exc:
|
|
165
|
+
# Don't retry timeouts — Ableton may have processed the command
|
|
166
|
+
if "Timeout" in str(exc):
|
|
167
|
+
raise
|
|
168
|
+
# Retry once with a fresh connection for non-timeout errors
|
|
169
|
+
self.disconnect()
|
|
170
|
+
self.connect()
|
|
171
|
+
response = self._send_raw(command)
|
|
172
|
+
except OSError:
|
|
160
173
|
# Retry once with a fresh connection
|
|
161
174
|
self.disconnect()
|
|
162
175
|
self.connect()
|
|
@@ -183,6 +196,15 @@ class AbletonConnection:
|
|
|
183
196
|
self._command_log.append(log_entry)
|
|
184
197
|
return response.get("result", {})
|
|
185
198
|
|
|
199
|
+
async def send_command_async(self, command_type: str, params: Optional[dict] = None) -> dict:
|
|
200
|
+
"""Async wrapper around send_command that avoids blocking the event loop.
|
|
201
|
+
|
|
202
|
+
Runs the blocking TCP send/receive in a thread pool executor so the
|
|
203
|
+
asyncio event loop remains responsive to other concurrent MCP tools.
|
|
204
|
+
"""
|
|
205
|
+
loop = asyncio.get_running_loop()
|
|
206
|
+
return await loop.run_in_executor(None, self.send_command, command_type, params)
|
|
207
|
+
|
|
186
208
|
# ------------------------------------------------------------------
|
|
187
209
|
# Command log
|
|
188
210
|
# ------------------------------------------------------------------
|
package/mcp_server/curves.py
CHANGED
|
@@ -277,10 +277,18 @@ def _square(duration: float, density: int, low: float, high: float,
|
|
|
277
277
|
return points
|
|
278
278
|
|
|
279
279
|
|
|
280
|
-
def _steps(values: list[float], duration: float,
|
|
281
|
-
|
|
280
|
+
def _steps(values: list[float], duration: float, start: float = 0.0,
|
|
281
|
+
end: float = 1.0, steps: int = 16, density: int = 16,
|
|
282
|
+
**_) -> list:
|
|
283
|
+
"""Quantized staircase from explicit value list or auto-generated from start/end.
|
|
284
|
+
|
|
285
|
+
If values is empty, generates a staircase with `steps` evenly spaced
|
|
286
|
+
levels from `start` to `end`.
|
|
287
|
+
"""
|
|
282
288
|
if not values:
|
|
283
|
-
|
|
289
|
+
# Auto-generate staircase from start/end with the given number of steps
|
|
290
|
+
n = max(steps, 2)
|
|
291
|
+
values = [start + (end - start) * i / (n - 1) for i in range(n)]
|
|
284
292
|
step_dur = duration / len(values)
|
|
285
293
|
return [
|
|
286
294
|
{"time": i * step_dur, "value": v, "duration": step_dur}
|
|
@@ -306,7 +314,7 @@ def _perlin(duration: float, density: int, center: float = 0.5,
|
|
|
306
314
|
|
|
307
315
|
def _hash_float(x: float, s: float) -> float:
|
|
308
316
|
"""Deterministic pseudo-random float from position + seed."""
|
|
309
|
-
h = hashlib.md5(f"{x:.6f}:{s:.6f}".encode()).hexdigest()
|
|
317
|
+
h = hashlib.md5(f"{x:.6f}:{s:.6f}".encode(), usedforsecurity=False).hexdigest()
|
|
310
318
|
return (int(h[:8], 16) / 0xFFFFFFFF) * 2.0 - 1.0
|
|
311
319
|
|
|
312
320
|
def _smoothstep(t: float) -> float:
|
|
@@ -355,7 +363,7 @@ def _brownian(duration: float, density: int, start: float = 0.5,
|
|
|
355
363
|
import hashlib
|
|
356
364
|
|
|
357
365
|
def _det_random(i: int, s: float) -> float:
|
|
358
|
-
h = hashlib.md5(f"{i}:{s:.6f}".encode()).hexdigest()
|
|
366
|
+
h = hashlib.md5(f"{i}:{s:.6f}".encode(), usedforsecurity=False).hexdigest()
|
|
359
367
|
return (int(h[:8], 16) / 0xFFFFFFFF) * 2.0 - 1.0
|
|
360
368
|
|
|
361
369
|
points = []
|
|
@@ -581,7 +589,7 @@ def _stochastic(duration: float, density: int, center: float = 0.5,
|
|
|
581
589
|
import hashlib
|
|
582
590
|
|
|
583
591
|
def _det_random(i: int, s: float) -> float:
|
|
584
|
-
h = hashlib.md5(f"{i}:{s:.6f}".encode()).hexdigest()
|
|
592
|
+
h = hashlib.md5(f"{i}:{s:.6f}".encode(), usedforsecurity=False).hexdigest()
|
|
585
593
|
return (int(h[:8], 16) / 0xFFFFFFFF) * 2.0 - 1.0
|
|
586
594
|
|
|
587
595
|
points = []
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Evaluation Fabric — unified evaluation layer for all engines."""
|