livepilot 1.27.2 → 1.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +10 -7
  3. package/bin/livepilot.js +97 -39
  4. package/livepilot/.Codex-plugin/plugin.json +1 -1
  5. package/livepilot/.claude-plugin/plugin.json +1 -1
  6. package/livepilot/skills/livepilot-core/SKILL.md +33 -1
  7. package/livepilot/skills/livepilot-core/references/atlas-tool-notes.md +69 -0
  8. package/livepilot/skills/livepilot-core/references/overview.md +18 -11
  9. package/livepilot/skills/livepilot-core/references/perception.md +125 -0
  10. package/livepilot/skills/livepilot-devices/references/device-parameter-units.md +66 -0
  11. package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
  12. package/livepilot/skills/livepilot-mix-engine/SKILL.md +8 -0
  13. package/livepilot/skills/livepilot-release/SKILL.md +1 -1
  14. package/livepilot/skills/livepilot-sample-engine/references/splice-tools-notes.md +56 -0
  15. package/livepilot/skills/livepilot-wonder/SKILL.md +6 -0
  16. package/m4l_device/LivePilot_Analyzer.amxd +0 -0
  17. package/m4l_device/livepilot_bridge.js +1 -1
  18. package/mcp_server/__init__.py +1 -1
  19. package/mcp_server/atlas/__init__.py +181 -40
  20. package/mcp_server/atlas/overlays.py +46 -3
  21. package/mcp_server/atlas/tools.py +226 -86
  22. package/mcp_server/audit/checks.py +50 -22
  23. package/mcp_server/audit/state.py +10 -2
  24. package/mcp_server/audit/tools.py +27 -6
  25. package/mcp_server/composer/develop/apply.py +7 -7
  26. package/mcp_server/composer/fast/apply.py +29 -23
  27. package/mcp_server/composer/framework/atlas_resolver.py +16 -1
  28. package/mcp_server/composer/full/apply.py +40 -34
  29. package/mcp_server/composer/full/engine.py +66 -32
  30. package/mcp_server/composer/tools.py +4 -3
  31. package/mcp_server/connection.py +67 -9
  32. package/mcp_server/creative_constraints/engine.py +10 -2
  33. package/mcp_server/creative_constraints/tools.py +24 -7
  34. package/mcp_server/curves.py +30 -7
  35. package/mcp_server/device_forge/builder.py +40 -11
  36. package/mcp_server/device_forge/models.py +9 -0
  37. package/mcp_server/device_forge/tools.py +30 -11
  38. package/mcp_server/experiment/engine.py +29 -22
  39. package/mcp_server/experiment/tools.py +15 -5
  40. package/mcp_server/m4l_bridge.py +69 -7
  41. package/mcp_server/memory/taste_graph.py +43 -0
  42. package/mcp_server/memory/technique_store.py +26 -3
  43. package/mcp_server/memory/tools.py +62 -4
  44. package/mcp_server/mix_engine/critics.py +187 -30
  45. package/mcp_server/mix_engine/models.py +21 -1
  46. package/mcp_server/mix_engine/state_builder.py +87 -8
  47. package/mcp_server/mix_engine/tools.py +16 -4
  48. package/mcp_server/performance_engine/tools.py +56 -8
  49. package/mcp_server/persistence/base_store.py +11 -0
  50. package/mcp_server/persistence/project_store.py +132 -8
  51. package/mcp_server/persistence/taste_store.py +90 -7
  52. package/mcp_server/preview_studio/engine.py +40 -10
  53. package/mcp_server/preview_studio/models.py +40 -0
  54. package/mcp_server/preview_studio/tools.py +56 -12
  55. package/mcp_server/project_brain/arrangement_graph.py +4 -0
  56. package/mcp_server/project_brain/models.py +2 -0
  57. package/mcp_server/project_brain/role_graph.py +13 -7
  58. package/mcp_server/reference_engine/gap_analyzer.py +58 -3
  59. package/mcp_server/reference_engine/profile_builder.py +47 -4
  60. package/mcp_server/reference_engine/tools.py +6 -0
  61. package/mcp_server/runtime/execution_router.py +51 -1
  62. package/mcp_server/runtime/tools.py +0 -1
  63. package/mcp_server/sample_engine/sources.py +0 -2
  64. package/mcp_server/sample_engine/tools.py +19 -38
  65. package/mcp_server/semantic_moves/mix_compilers.py +276 -51
  66. package/mcp_server/semantic_moves/performance_compilers.py +51 -17
  67. package/mcp_server/semantic_moves/resolvers.py +45 -0
  68. package/mcp_server/semantic_moves/sound_design_compilers.py +14 -6
  69. package/mcp_server/semantic_moves/tools.py +80 -2
  70. package/mcp_server/semantic_moves/transition_compilers.py +26 -9
  71. package/mcp_server/server.py +26 -24
  72. package/mcp_server/session_continuity/tracker.py +51 -3
  73. package/mcp_server/song_brain/builder.py +47 -5
  74. package/mcp_server/song_brain/tools.py +21 -7
  75. package/mcp_server/sound_design/critics.py +1 -0
  76. package/mcp_server/splice_client/client.py +117 -33
  77. package/mcp_server/splice_client/http_bridge.py +15 -3
  78. package/mcp_server/splice_client/quota.py +28 -0
  79. package/mcp_server/stuckness_detector/detector.py +8 -5
  80. package/mcp_server/synthesis_brain/adapters/drift.py +13 -0
  81. package/mcp_server/synthesis_brain/adapters/meld.py +13 -0
  82. package/mcp_server/tools/_analyzer_engine/sample.py +36 -10
  83. package/mcp_server/tools/_perception_engine.py +6 -0
  84. package/mcp_server/tools/agent_os.py +4 -1
  85. package/mcp_server/tools/analyzer.py +198 -209
  86. package/mcp_server/tools/arrangement.py +7 -4
  87. package/mcp_server/tools/automation.py +24 -4
  88. package/mcp_server/tools/browser.py +25 -11
  89. package/mcp_server/tools/clips.py +6 -0
  90. package/mcp_server/tools/composition.py +33 -2
  91. package/mcp_server/tools/devices.py +53 -53
  92. package/mcp_server/tools/generative.py +14 -14
  93. package/mcp_server/tools/harmony.py +7 -7
  94. package/mcp_server/tools/mixing.py +4 -4
  95. package/mcp_server/tools/planner.py +68 -6
  96. package/mcp_server/tools/research.py +20 -2
  97. package/mcp_server/tools/theory.py +10 -10
  98. package/mcp_server/tools/transport.py +7 -2
  99. package/mcp_server/transition_engine/critics.py +13 -1
  100. package/mcp_server/user_corpus/tools.py +30 -1
  101. package/mcp_server/wonder_mode/engine.py +82 -9
  102. package/mcp_server/wonder_mode/session.py +32 -10
  103. package/mcp_server/wonder_mode/tools.py +14 -1
  104. package/package.json +1 -1
  105. package/remote_script/LivePilot/__init__.py +1 -1
  106. package/remote_script/LivePilot/arrangement.py +93 -33
  107. package/remote_script/LivePilot/browser.py +60 -4
  108. package/remote_script/LivePilot/devices.py +132 -62
  109. package/remote_script/LivePilot/mixing.py +31 -5
  110. package/remote_script/LivePilot/server.py +94 -22
  111. package/remote_script/LivePilot/transport.py +11 -0
  112. package/requirements.txt +5 -5
  113. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,71 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.27.3 — 2026-07-10
4
+
5
+ Deep-review remediation campaign (2026-07-09, on top of the 2026-06-24 fix batch): event-loop
6
+ blocking eliminated tree-wide, release-pipeline gates hardened, atlas scan truncation fixed,
7
+ Splice connection health, state-layer race/replay guards, docs drift automation, and +262 tests
8
+ (4326 → 4597 passing). No change to the tool surface (467 tools / 56 domains).
9
+
10
+ ### Fixed — event loop (systemic)
11
+ - Every remaining blocking call in async tool paths offloaded (~80 sites across 13 files):
12
+ the composer fast/full/develop apply executors, the shared plan-step executor
13
+ (`execution_router._execute_step_async`), preview/experiment paths, analyzer helper call
14
+ sites, automation session-record, agent_os iteration, device-forge/file I/O, and lifespan
15
+ subprocess probes. New canonical wrapper `AbletonConnection.send_command_async()`.
16
+ - The AST regression guard now scans ALL of `mcp_server/` (was analyzer.py-only) with
17
+ one-hop transitive detection and file-I/O/subprocess patterns (`scripts/scan_async_blocking.py`).
18
+
19
+ Live-verified on Ableton 12.4.2 (2026-07-10): per-track volume reporting, force_arrangement
20
+ with return tracks, sidechain name resolution (both casings), analyzer bridge reconnect, and a
21
+ full 40k-device library rescan with zero category truncation.
22
+
23
+ ### Fixed — correctness
24
+ - Sidechain source matching gained a case-insensitive EXACT tier (found live: Live 12.4
25
+ routing menus can list bare unprefixed track names, where the "-name" suffix fallback
26
+ never fires); matching ladder extracted into a tested helper.
27
+ - `audit_layer` §5.1 timbre check was a silent double no-op (wrong call signature + uppercase
28
+ band table vs lowercase producers) — now plumbs cached analyzer spectrum and case-folds.
29
+ - Atlas scans no longer truncate alphabetically at 1000 entries/category (drum kits previously
30
+ cut off before reaching most of the alphabet); scans record per-category counts + truncation
31
+ flags, and atlas searches warn when a truncated category is queried. Rescan required to
32
+ rebuild an existing user atlas (`scan_full_library(force=True)`).
33
+ - Semantic mix/sound-design/transition/performance moves now nudge track volume RELATIVE to the
34
+ current level (bounded, direction-safe) instead of writing absolute constants; the Remote
35
+ Script now reports per-track volume in `get_session_info`.
36
+ - Splice client marks itself degraded on RPC failure and self-heals with a one-shot reconnect —
37
+ a Splice desktop restart no longer yields silent fake "0 results" for the session; quota
38
+ check-and-record is atomic; HTTP retry no longer sleeps after the final attempt.
39
+ - Preview/wonder cached plans carry a session fingerprint and refuse commit with STATE_ERROR
40
+ when the session changed shape; shared caches are lock-guarded; persisted taste/project
41
+ stores back up before any version-mismatch reset; `song_brain` ids are content-aware.
42
+ - `get_emotional_arc` harmonic-instability term computed (was structurally zero);
43
+ flucoma probe no longer reports empty dirs as installed; composer engine renumbers layers
44
+ after unresolved-sample drops on the experiment-escalation path.
45
+
46
+ ### Changed — release gates & CI
47
+ - New CI jobs: MCPB bundle build (asset previously shipped missing for 4 releases),
48
+ Python 3.11 compatibility for `remote_script/` (compileall + vermin), content-level
49
+ .amxd freeze check (full bridge command set, not just the version string).
50
+ - `bin/livepilot.js` venv staleness keyed on a requirements.txt content hash (hardcoded import
51
+ list had drifted — upgrading users silently never installed the Splice gRPC dependencies).
52
+ - `sync_metadata.py` validates JSON manifests version-field-by-field (caught a live
53
+ server.json split-version); docs Domain Map is now generated from the live registry;
54
+ banner assets and README What's New are drift-guarded.
55
+
56
+ ### Changed — performance & analysis quality
57
+ - Server import ~2.0s → ~0.9s (lazy overlay index + libyaml CSafeLoader); atlas duplicate
58
+ warnings throttled; test suite wall-clock ~41s → ~32s.
59
+ - Mix-critic confidence values are data-derived (sample size, measured-vs-heuristic basis,
60
+ margin) instead of hardcoded literals; `analyze_mix`/`get_mix_issues` accept
61
+ `target_style="loud_master"` to suppress the over-compressed flag for intentionally loud
62
+ masters; Wonder Mode ranking surfaces a `boldest_executable` slot alongside the safe pick.
63
+ - Security hardening: corpus plugin-id path validation, loopback-only UDP analyzer ingestion,
64
+ competing-TCP-client identification in eviction errors.
65
+
66
+ ### Changed — dependencies
67
+ - **2026-06-25** — Raised the Python floor to 3.12: numpy>=2.5.0 and scipy>=1.18.0 declare `Requires-Python >=3.12`, so the prior 3.11 floor blocked both dependency bumps across the CI matrix. CI now tests only Python 3.12; the install-time Python-version diagnostic and manifest/docs floor references were updated to match. `remote_script/` stays 3.11-syntax-compatible for Ableton's embedded Python (Live 12.3) — the CI matrix change does not relax that constraint.
68
+
3
69
  ## v1.27.2 — 2026-06-23
4
70
 
5
71
  Maintenance release: M4L bridge response-correlation + chunk-reassembly hardening, plan-routing fixes, a Python 3.11 floor with clearer install diagnostics, and a Remote Script Group-track crash guard. No change to the tool surface (467 tools / 56 domains). Re-frozen LivePilot_Analyzer.amxd (analyzer reports 1.27.2).
package/README.md CHANGED
@@ -38,14 +38,17 @@
38
38
 
39
39
  ---
40
40
 
41
- ## What's New in v1.27.1
41
+ ## What's New in v1.27.3
42
42
 
43
- A maintenance release that fixes 35 issues from a deep audit and restores tools that had silently broken:
43
+ A deep-review remediation release ~150 fixes across two audit campaigns, no change to the tool surface (467 tools / 56 domains):
44
44
 
45
- - **Restored tools** — `augment_with_samples`, `get_composition_plan`, `propose_composer_branches`, `check_clip_key_consistency`, and `compare_phrase_renders` were crashing or returning empty results; they now work.
46
- - **Recursive plugin scanning (#44)** — the User Corpus scanner now finds plugins nested in vendor subfolders (e.g. `VST3/<Vendor>/Plugin.vst3`) instead of only the top level.
47
- - **Truer analysis** — reference-gap, hook-salience, dynamics, drop-detection, harmony-slot, and grader fixes that previously produced fabricated or empty results.
48
- - **Safer & faster** — Splice credit-gating fixed, blocking sample I/O moved off the event loop, unbounded tool responses capped, and the M4L bridge no longer loses responses on UDP reordering.
45
+ - **Event-loop blocking eliminated tree-wide** — every remaining blocking call in async tool paths (composer apply executors, the shared plan-step executor, preview/experiment paths, ~80 sites in 13 files) now offloads to a worker thread; a repo-wide AST regression guard keeps it that way. Long composes no longer freeze concurrent tools or the analyzer bridge.
46
+ - **Atlas scans no longer truncate** — library scans previously capped each category at 1,000 entries alphabetically (most drum one-shots were unreachable); the cap is now 25,000 with per-category truncation flags and rescan warnings. Run `scan_full_library(force=True)` once to rebuild your atlas.
47
+ - **Splice self-heals** — a Splice desktop restart no longer silently turns every search into fake "0 results"; the client marks itself degraded and reconnects on the next call.
48
+ - **Safer state** — cached preview/wonder plans carry a session fingerprint and refuse to replay against a session that changed shape; persisted taste/project stores back up before any reset.
49
+ - **Stronger release gates** — the MCPB bundle, .amxd freeze content, and Python 3.11 Remote Script compatibility are now all CI-enforced.
50
+ - **Python 3.12 floor** for the MCP server (numpy ≥2.5 / scipy ≥1.18); the Remote Script stays 3.11-compatible for Ableton's embedded Python.
51
+ - **v1.27.1** fixed 35 issues from a deep audit and restored tools that had silently broken (`augment_with_samples`, `get_composition_plan`, `propose_composer_branches`, `check_clip_key_consistency`, `compare_phrase_renders`), plus recursive installed-plugin scanning.
49
52
  - **v1.27.0** added two read-only Live 12.4 capability-probe tools (`probe_link_audio`, `probe_stem_workflow`).
50
53
 
51
54
  Full details in the [CHANGELOG](CHANGELOG.md).
@@ -751,7 +754,7 @@ npx livepilot --version # Show version
751
754
  | Requirement | Minimum |
752
755
  |-------------|---------|
753
756
  | Ableton Live | **12** (any edition). Suite required for Max for Live bridge and stock instruments |
754
- | Python | 3.11+ (numpy/scipy ship no wheels for 3.9/3.10) |
757
+ | Python | 3.12+ (numpy>=2.5 / scipy>=1.18 require Python 3.12) |
755
758
  | Node.js | 18+ |
756
759
  | OS | macOS / Windows |
757
760
  | Splice | Desktop app with downloaded samples (optional — enables SQLite metadata search) |
package/bin/livepilot.js CHANGED
@@ -15,12 +15,12 @@ const REQUIREMENTS = path.join(ROOT, "requirements.txt");
15
15
  // Python detection
16
16
  // ---------------------------------------------------------------------------
17
17
 
18
- // Minimum Python is 3.11, NOT 3.9: numpy>=2.4.6 and scipy>=1.17.1 (see
19
- // requirements.txt) publish no wheels and declare requires-python ">=3.11".
20
- // A 3.9/3.10 interpreter passes a looser gate, the venv is created, then
21
- // `pip install` aborts with a cryptic "no matching distribution" the exact
22
- // install failure users hit. Gate here so we fail early with a clear message.
23
- const MIN_PY_MINOR = 11;
18
+ // Minimum Python is 3.12: numpy>=2.5.0 and scipy>=1.18.0 (see requirements.txt)
19
+ // declare requires-python ">=3.12". An older interpreter passes a looser gate,
20
+ // the venv is created, then `pip install` aborts with a cryptic "no matching
21
+ // distribution" the exact install failure users hit. Gate here so we fail
22
+ // early with a clear message.
23
+ const MIN_PY_MINOR = 12;
24
24
 
25
25
  function findPython() {
26
26
  // On Windows, also try the "py -3" launcher which avoids the
@@ -47,7 +47,7 @@ function findPython() {
47
47
  const actualArgs = cmd === "py" ? ["-3"] : [];
48
48
  return { cmd: actualCmd, version: out, prefixArgs: actualArgs };
49
49
  }
50
- // Found Python 3 but below 3.11 — remember the newest for diagnostics.
50
+ // Found Python 3 but below 3.12 — remember the newest for diagnostics.
51
51
  if (major === 3 && (!tooOld || minor > tooOld.minor)) {
52
52
  tooOld = { version: out, minor };
53
53
  }
@@ -122,8 +122,8 @@ function pipInstall(venvPy) {
122
122
  console.error("");
123
123
  console.error("LivePilot: dependency installation failed.");
124
124
  if (/No matching distribution|requires-python|Could not find a version/i.test(stderr)) {
125
- console.error(" Most likely your Python is too old — LivePilot needs Python >= 3.11");
126
- console.error(" (numpy/scipy ship no wheels for 3.9/3.10). Install 3.11+, delete the");
125
+ console.error(" Most likely your Python is too old — LivePilot needs Python >= 3.12");
126
+ console.error(" (numpy>=2.5 / scipy>=1.18 require Python 3.12). Install 3.12+, delete the");
127
127
  console.error(" .venv folder, and retry.");
128
128
  }
129
129
  const tail = stderr.split("\n").filter(Boolean).slice(-12);
@@ -136,6 +136,48 @@ function pipInstall(venvPy) {
136
136
  }
137
137
  }
138
138
 
139
+ /**
140
+ * Content hash of requirements.txt — the venv staleness signal.
141
+ *
142
+ * The previous check was a hardcoded import list that silently drifted from
143
+ * requirements.txt (grpcio/protobuf were added for the Splice gRPC surface
144
+ * but never joined the list, so upgrading users kept a venv without them and
145
+ * the feature silently disabled itself). Hashing the file makes staleness
146
+ * detection automatically correct for every future dependency change.
147
+ */
148
+ function requirementsHash() {
149
+ const crypto = require("crypto");
150
+ const reqs = fs.readFileSync(path.join(ROOT, "requirements.txt"));
151
+ return crypto.createHash("sha256").update(reqs).digest("hex");
152
+ }
153
+
154
+ function venvStampPath() {
155
+ return path.join(ROOT, VENV_DIR, ".requirements-sha256");
156
+ }
157
+
158
+ function writeVenvStamp() {
159
+ try {
160
+ fs.writeFileSync(venvStampPath(), requirementsHash() + "\n");
161
+ } catch {
162
+ // Non-fatal: worst case the next run reinstalls.
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Pure decision function for venv staleness — extracted from ensureVenv so
168
+ * the reinstall/reuse/create branching can be unit-tested without touching
169
+ * the filesystem or spawning pip/venv. Behavior-identical to the inline
170
+ * logic it replaces:
171
+ * - no venv on disk -> "create"
172
+ * - venv exists, stamp matches hash -> "reuse"
173
+ * - venv exists, stamp missing/mismatched -> "update"
174
+ */
175
+ function decideVenvAction(venvExists, storedStamp, currentHash) {
176
+ if (!venvExists) return "create";
177
+ if (storedStamp === currentHash) return "reuse";
178
+ return "update";
179
+ }
180
+
139
181
  /**
140
182
  * Ensure a local .venv exists with dependencies installed.
141
183
  * Returns the path to the venv Python binary.
@@ -143,25 +185,31 @@ function pipInstall(venvPy) {
143
185
  function ensureVenv(systemPython, prefixArgs) {
144
186
  const prefix = prefixArgs || [];
145
187
  const venvPy = venvPython();
188
+ const venvExists = fs.existsSync(venvPy);
146
189
 
147
- // Check if venv already exists and has our deps
148
- if (fs.existsSync(venvPy)) {
190
+ let stamp = null;
191
+ if (venvExists) {
149
192
  try {
150
- execFileSync(venvPy, ["-c", "import fastmcp; import midiutil; import pretty_midi; import numpy; import pyloudnorm; import soundfile; import scipy; import mutagen"], {
151
- encoding: "utf-8",
152
- timeout: 10000,
153
- stdio: "pipe",
154
- });
155
- return venvPy; // venv exists and all deps importable
193
+ stamp = fs.readFileSync(venvStampPath(), "utf-8").trim();
156
194
  } catch {
157
- // venv exists but deps missing — reinstall
158
- console.error("LivePilot: reinstalling Python dependencies...");
159
- pipInstall(venvPy);
160
- return venvPy;
195
+ stamp = null; // pre-hash venv (or stamp deleted)verify by reinstall
161
196
  }
162
197
  }
163
198
 
164
- // Create venv from scratch
199
+ const action = decideVenvAction(venvExists, stamp, requirementsHash());
200
+
201
+ if (action === "reuse") {
202
+ return venvPy; // venv exists and was installed from this exact requirements.txt
203
+ }
204
+
205
+ if (action === "update") {
206
+ console.error("LivePilot: requirements changed — updating Python dependencies...");
207
+ pipInstall(venvPy);
208
+ writeVenvStamp();
209
+ return venvPy;
210
+ }
211
+
212
+ // action === "create"
165
213
  console.error("LivePilot: setting up Python environment (first run)...");
166
214
  execFileSync(systemPython, [...prefix, "-m", "venv", VENV_DIR], {
167
215
  cwd: ROOT,
@@ -171,6 +219,7 @@ function ensureVenv(systemPython, prefixArgs) {
171
219
 
172
220
  console.error("LivePilot: installing dependencies...");
173
221
  pipInstall(venvPython());
222
+ writeVenvStamp();
174
223
 
175
224
  return venvPython();
176
225
  }
@@ -309,12 +358,12 @@ async function doctor() {
309
358
  if (pyInfo && !pyInfo.tooOld) {
310
359
  console.log(" Python: %s (%s)", pyInfo.version, pyInfo.cmd);
311
360
  } else if (pyInfo && pyInfo.tooOld) {
312
- console.log(" Python: %s found, but LivePilot needs >= 3.11", pyInfo.version);
313
- console.log(" Fix: install Python 3.11+ (numpy/scipy ship no wheels for 3.9/3.10)");
361
+ console.log(" Python: %s found, but LivePilot needs >= 3.12", pyInfo.version);
362
+ console.log(" Fix: install Python 3.12+ (numpy>=2.5 / scipy>=1.18 require Python 3.12)");
314
363
  ok = false;
315
364
  } else {
316
- console.log(" Python: NOT FOUND (need >= 3.11)");
317
- console.log(" Fix: install Python 3.11+ and add to PATH");
365
+ console.log(" Python: NOT FOUND (need >= 3.12)");
366
+ console.log(" Fix: install Python 3.12+ and add to PATH");
318
367
  ok = false;
319
368
  }
320
369
 
@@ -737,12 +786,12 @@ async function setup() {
737
786
  if (pyInfo && !pyInfo.tooOld) {
738
787
  console.log(" ✓ %s", pyInfo.version);
739
788
  } else if (pyInfo && pyInfo.tooOld) {
740
- console.log(" ✗ %s found, but LivePilot needs Python >= 3.11", pyInfo.version);
741
- console.log(" (numpy/scipy ship no wheels for 3.9/3.10 — pip would fail)");
789
+ console.log(" ✗ %s found, but LivePilot needs Python >= 3.12", pyInfo.version);
790
+ console.log(" (numpy>=2.5 / scipy>=1.18 require Python 3.12 — pip would fail)");
742
791
  console.log(" Install: brew install python@3.12 (macOS) or python.org (Windows)");
743
792
  ok = false;
744
793
  } else {
745
- console.log(" ✗ Python >= 3.11 not found");
794
+ console.log(" ✗ Python >= 3.12 not found");
746
795
  console.log(" Install: brew install python@3.12 (macOS) or python.org (Windows)");
747
796
  ok = false;
748
797
  }
@@ -784,7 +833,7 @@ async function setup() {
784
833
  ok = false;
785
834
  }
786
835
  } else if (pyInfo && pyInfo.tooOld) {
787
- console.log(" ⊘ Skipped (%s found, need Python >= 3.11)", pyInfo.version);
836
+ console.log(" ⊘ Skipped (%s found, need Python >= 3.12)", pyInfo.version);
788
837
  } else {
789
838
  console.log(" ⊘ Skipped (no Python)");
790
839
  }
@@ -974,12 +1023,12 @@ async function main() {
974
1023
  const pyInfo = findPython();
975
1024
  if (!pyInfo || pyInfo.tooOld) {
976
1025
  if (pyInfo && pyInfo.tooOld) {
977
- console.error("Error: found %s, but LivePilot requires Python >= 3.11.", pyInfo.version);
978
- console.error(" numpy>=2.4.6 and scipy>=1.17.1 publish no wheels for Python 3.9/3.10,");
979
- console.error(" so dependency installation would fail. Install Python 3.11 or newer.");
1026
+ console.error("Error: found %s, but LivePilot requires Python >= 3.12.", pyInfo.version);
1027
+ console.error(" numpy>=2.5.0 and scipy>=1.18.0 require Python >= 3.12,");
1028
+ console.error(" so dependency installation would fail. Install Python 3.12 or newer.");
980
1029
  } else {
981
- console.error("Error: Python >= 3.11 is required but was not found.");
982
- console.error(" Install Python 3.11+ and ensure 'python3' or 'python' is on your PATH.");
1030
+ console.error("Error: Python >= 3.12 is required but was not found.");
1031
+ console.error(" Install Python 3.12+ and ensure 'python3' or 'python' is on your PATH.");
983
1032
  }
984
1033
  console.error("");
985
1034
  console.error(" macOS: brew install python@3.12");
@@ -1026,7 +1075,16 @@ async function main() {
1026
1075
  });
1027
1076
  }
1028
1077
 
1029
- main().catch((err) => {
1030
- console.error(err);
1031
- process.exit(1);
1032
- });
1078
+ // Only auto-run the CLI when this file is executed directly (`node
1079
+ // bin/livepilot.js ...` or `npx livepilot ...`). When `require()`d as a
1080
+ // module — e.g. from tests exercising `decideVenvAction` in isolation —
1081
+ // skip the side-effecting entrypoint. Behavior-identical for real CLI
1082
+ // invocations; this guard only matters when the file is `require()`d.
1083
+ if (require.main === module) {
1084
+ main().catch((err) => {
1085
+ console.error(err);
1086
+ process.exit(1);
1087
+ });
1088
+ }
1089
+
1090
+ module.exports = { decideVenvAction, requirementsHash, venvStampPath };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.27.2",
3
+ "version": "1.27.3",
4
4
  "description": "Agentic production system for Ableton Live 12 \u2014 467 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, neo-Riemannian harmony, Euclidean rhythm, species counterpoint, MIDI I/O",
5
5
  "author": {
6
6
  "name": "Pilot Studio"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.27.2",
3
+ "version": "1.27.3",
4
4
  "description": "Agentic production system for Ableton Live 12 \u2014 467 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, neo-Riemannian harmony, Euclidean rhythm, species counterpoint, MIDI I/O",
5
5
  "author": {
6
6
  "name": "Pilot Studio"
@@ -47,7 +47,7 @@ Agentic production system for Ableton Live 12. 467 tools across 56 domains, thre
47
47
  - **Parameter ranges are NOT always 0-1.** Auto Filter Frequency is 20-135. Bit Depth is 1-16. Always read `value_string` to see actual units.
48
48
  16. **NEVER apply automation recipes without understanding the target parameter's range** — recipes generate 0-1 curves that get auto-scaled for device parameters, but always verify the result
49
49
  17. **LivePilot_Analyzer must be LAST on master chain** — always place after ALL effects (EQ, Compressor, Utility, etc.) so it measures the final post-processing output, not the raw signal. When loading effects on master, either load them before the analyzer or move the analyzer to end afterward
50
- 18. **Remote Script reload workflow** — after any edit to `remote_script/LivePilot/*.py`: run `npx livepilot --install` (NOT `node installer/install.js` — that raw file only module-exports the install function and silently no-ops as a script), then call `reload_handlers` (MCP tool, domain: diagnostics). NEVER instruct the user to toggle the Control Surface in Live Preferences. The tool uses pkgutil + importlib to re-fire `@register` decorators in-place in <1s while the TCP connection stays open. Standard procedure for every handler change — not just releases
50
+ 18. **Remote Script reload workflow** — after any edit to `remote_script/LivePilot/*.py`: install, then call `reload_handlers` (MCP tool, domain: diagnostics). From a LOCAL CHECKOUT the install command is `node bin/livepilot.js --install` — `npx livepilot --install` fetches the PUBLISHED npm package and overwrites local edits with stale code. Use `npx livepilot --install` only for the published package (end-user installs). Either way, NOT `node installer/install.js` — that raw file only module-exports the install function and silently no-ops as a script. NEVER instruct the user to toggle the Control Surface in Live Preferences. The tool uses pkgutil + importlib to re-fire `@register` decorators in-place in <1s while the TCP connection stays open. Standard procedure for every handler change — not just releases
51
51
 
52
52
  ## Tool Speed Tiers
53
53
 
@@ -79,6 +79,38 @@ Report ALL errors to the user immediately. Common failure modes:
79
79
  - **M4L Analyzer not connected** — if `get_master_spectrum` errors with "Analyzer not detected", call `ensure_analyzer_on_master`. If it returns `install_required`, call `install_m4l_device(source_path="<repo>/m4l_device/LivePilot_Analyzer.amxd")` and retry. If it errors with "UDP bridge not connected", try `reconnect_bridge` first
80
80
  - **Another client connected** — Remote Script only accepts one TCP client on port 9878. If you see this error, the MCP server is already connected. Use MCP tools instead of raw TCP
81
81
 
82
+ ## Response Fields You Must Check
83
+
84
+ These fields were added to existing tool responses. They aren't optional
85
+ extras — each one changes what you're allowed to claim to the user.
86
+
87
+ - **`degraded_reason`** (`enter_wonder_mode` / Wonder Mode) — non-empty when
88
+ fewer than 3 of the returned variants are actually executable, or when no
89
+ matching moves were found and variants are cold-start fallbacks. Contract:
90
+ if `degraded_reason` is set, do NOT present the set as "three genuinely
91
+ different options" — disclose the degradation honestly. See
92
+ `livepilot-wonder`.
93
+ - **`unenforced_constraints`** (`apply_creative_constraint_set` / Creative
94
+ Constraints) — lists constraint names that are advisory-only; the engine
95
+ cannot mechanically verify them against compiled steps. Contract: for every
96
+ name in this list, YOU must self-police that constraint manually — the
97
+ tool returning `valid: true` does not mean an advisory constraint wasn't
98
+ violated.
99
+ - **`measured` / `severity_basis`** (`get_masking_report` / Mix Engine) — a
100
+ masking entry's `severity` is either a real per-track spectral-overlap
101
+ measurement (`measured=True`, `severity_basis="spectral_overlap"`) or a
102
+ role-pair heuristic constant (`measured=False`,
103
+ `severity_basis="role_heuristic"`). Contract: treat `measured=False`
104
+ entries as low-confidence priors, not verified problems — solo the tracks
105
+ and read `get_master_spectrum` before taking a mixing action based on them
106
+ (§3 Analysis Before Action). See `livepilot-mix-engine`.
107
+ - **`load_via` / `browse_hint`** (Atlas — `atlas_search`, `atlas_suggest`,
108
+ `atlas_device_info`, etc.) — set when an atlas entry's `uri` is cleared
109
+ because it's a known-broken M4L pack-instrument reference. Contract: when
110
+ `load_via == "preset"`, do NOT call `load_browser_item` with the atlas
111
+ `uri` (it's empty/invalid) — call `search_browser` with `browse_hint`
112
+ instead to resolve a real URI first.
113
+
82
114
  ## Technique Memory
83
115
 
84
116
  Three modes:
@@ -0,0 +1,69 @@
1
+ # Atlas Tool Notes
2
+
3
+ Implementation history and rationale for `mcp_server/atlas/tools.py`
4
+ tools. The tool docstrings carry the operational contract (params,
5
+ return shape, behavior); this file carries the bug history and
6
+ step-by-step internals that explain *why* a tool behaves a certain way,
7
+ for when that context is actually needed.
8
+
9
+ ## `scan_full_library` — scan cap history
10
+
11
+ `max_per_category` defaults to 25000, matching the remote script's own
12
+ default. The original hardcoded 1000 cap silently truncated large
13
+ categories in browser-tree (alphabetical) order — e.g. `drum_kits`
14
+ stopped at "Crash" (0 kicks, 2 hats), and the `samples` category alone
15
+ has ~22,000 items per the browser tree, so a "1000 samples" count was
16
+ wrong by a factor of 22 (BUG-2026-04-22#12). Raise the cap further for
17
+ even bigger libraries; lower it for fast smoke scans.
18
+
19
+ `truncated_categories` / `stats.category_truncated` are persisted into
20
+ `device_atlas.json` so `AtlasManager` can warn future
21
+ `atlas_search`/`atlas_suggest` calls that touch a truncated category
22
+ without requiring a fresh scan first (P3-47).
23
+
24
+ Scans always write to the user atlas path
25
+ (`~/.livepilot/atlas/device_atlas.json`), never the bundled baseline —
26
+ this keeps personal inventories (packs, user_library, plugins) out of
27
+ the repo and surviving npm updates (v1.22.0). Enrichments are still
28
+ read from the bundled package.
29
+
30
+ ## `atlas_describe_chain` — internals
31
+
32
+ Free-text → chain proposal pipeline, mirroring `splice_describe_sound`
33
+ for the device library (`atlas_chain_suggest` is the structured-input
34
+ sibling — role + genre instead of a sentence):
35
+
36
+ 1. Parse role hints from the description (bass/lead/pad/keys/
37
+ percussion/drums/vocal/fx keyword buckets)
38
+ 2. Parse aesthetic hints — artist names map to genre/character tags
39
+ (cross-reference `artist-vocabularies.md`), plus explicit genre
40
+ names and character words (warm/cold/bright/dark/lush/...)
41
+ 3. Search the atlas (factory + user overlay namespaces) with those terms
42
+ 4. Propose the top devices per role with brief rationale, then take the
43
+ top suggestion per role as a simple ordered `chain_proposal`
44
+
45
+ Does not autoload anything — the caller reviews/adjusts, then executes
46
+ via `load_browser_item` + effects.
47
+
48
+ ## `atlas_techniques_for_device` — index
49
+
50
+ Backed by the reverse-index file `device_techniques_index.json`
51
+ (auto-generated from the knowledge base — regenerate via the
52
+ post-v1.17 reverse-index builder script when adding new techniques;
53
+ rare, since most additions happen through enrichment YAMLs that the
54
+ index reads directly). `kind` values: `signature_technique` (from the
55
+ device's own atlas entry), `sample_technique` (from
56
+ `sample-techniques.md`), `sound_design_principle` (from
57
+ `sound-design-deep.md`).
58
+
59
+ ## `atlas_search` — overlay budget split
60
+
61
+ Searches both the bundled factory atlas (5,264 devices / 33 packs) and
62
+ the user-local overlay corpus (`~/.livepilot/atlas-overlays/` — user-
63
+ scanned Max devices, racks, plugin presets, AI-synthesized plugin
64
+ identity YAMLs). When both sources have hits, `limit` splits roughly
65
+ 50/50 (factory gets the rounding-up extra slot); a source with zero
66
+ hits doesn't consume budget. M4L pack instruments occasionally carry a
67
+ bogus `query:Synths#` URI in the atlas — `atlas_search` clears it and
68
+ surfaces a `browse_hint` so callers don't hit `INVALID_PARAM` from
69
+ `load_browser_item` (LIVE#3).
@@ -1,4 +1,4 @@
1
- # LivePilot v1.27.2 — Architecture & Tool Reference
1
+ # LivePilot v1.27.3 — Architecture & Tool Reference
2
2
 
3
3
  Agentic production system for Ableton Live 12. 467 tools across 56 domains. Device atlas (5264 devices, 120 enriched, 47 with aesthetic-tagged `signature_techniques`), spectral perception (M4L analyzer with 9-band FFT — sub_low / sub / low / low_mid / mid / high_mid / high / presence / air), 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, **LIVE Splice describe-a-sound + variations via captured GraphQL endpoints (v1.17)**, drum-rack pad-by-pad construction, live dead-device detection via meter sampling, role-aware Simpler defaults, session-record arrangement-automation workaround.
4
4
 
@@ -44,9 +44,16 @@ A flat tool list lets the AI press buttons. LivePilot's three layers give it con
44
44
 
45
45
  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."
46
46
 
47
- ## The 467 Tools What Each One Does
47
+ ## Core-Domain Reference (~228 tools, 13 of 56 domains)
48
48
 
49
- ### Transport (12) Playback, tempo, global state, diagnostics
49
+ This section documents the 13 highest-traffic domains in prose (what each
50
+ tool does, when to reach for it). It is intentionally NOT exhaustive — the
51
+ remaining domains (sample_engine, atlas, agent_os, wonder_mode, and the rest
52
+ of the Creative Intelligence layer) are covered by their own domain skills
53
+ and by the auto-generated **[Tool Catalog](../../../../docs/manual/tool-catalog.md)**,
54
+ which lists all 467 tools across all 56 domains.
55
+
56
+ ### Transport (showing 12 of 21) — Playback, tempo, global state, diagnostics
50
57
 
51
58
  | Tool | What it does | Key params |
52
59
  |------|-------------|------------|
@@ -63,7 +70,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
63
70
  | `get_recent_actions` | Returns log of recent commands sent to Ableton (newest first) | `limit` (1-50, default 20) |
64
71
  | `get_session_diagnostics` | Analyzes session for issues: armed tracks, solo leftovers, unnamed tracks, empty clips | — |
65
72
 
66
- ### Tracks (14) — Create, delete, configure, group tracks
73
+ ### Tracks (showing 14 of 21) — Create, delete, configure, group tracks
67
74
 
68
75
  | Tool | What it does | Key params |
69
76
  |------|-------------|------------|
@@ -82,7 +89,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
82
89
  | `set_group_fold` | Folds/unfolds a group track | `track_index`, `folded` (bool) |
83
90
  | `set_track_input_monitoring` | Sets input monitoring state | `track_index`, `state` (0=In, 1=Auto, 2=Off) |
84
91
 
85
- ### Clips (11) — Clip lifecycle, properties, warp
92
+ ### Clips (showing 11 of 16) — Clip lifecycle, properties, warp
86
93
 
87
94
  | Tool | What it does | Key params |
88
95
  |------|-------------|------------|
@@ -122,7 +129,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
122
129
  - `velocity_deviation` — -127.0 to 127.0
123
130
  - `release_velocity` — 0.0-127.0
124
131
 
125
- ### Devices (15) — Instruments, effects, racks, 12.3+ device insertion
132
+ ### Devices (showing 15 of 42) — Instruments, effects, racks, 12.3+ device insertion
126
133
 
127
134
  | Tool | What it does | Key params |
128
135
  |------|-------------|------------|
@@ -142,7 +149,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
142
149
  | `set_chain_volume` | Sets volume of a rack chain | `track_index`, `device_index`, `chain_index`, `volume` |
143
150
  | `get_device_presets` | Lists presets for a device (audio effects, instruments, MIDI effects) | `device_name` |
144
151
 
145
- ### Scenes (8) — Scene management
152
+ ### Scenes (showing 8 of 12) — Scene management
146
153
 
147
154
  | Tool | What it does | Key params |
148
155
  |------|-------------|------------|
@@ -180,7 +187,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
180
187
  | `search_browser` | Searches the browser | `query` |
181
188
  | `load_browser_item` | Loads a browser item onto a track — **`uri` MUST come from `search_browser` results, NEVER invented** | `track_index`, `uri` |
182
189
 
183
- ### Arrangement (20) — Timeline, recording, cue points, arrangement notes
190
+ ### Arrangement (showing 20 of 21) — Timeline, recording, cue points, arrangement notes
184
191
 
185
192
  | Tool | What it does | Key params |
186
193
  |------|-------------|------------|
@@ -205,7 +212,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
205
212
  | `jump_to_cue` | Jumps to a cue point by index | `cue_index` |
206
213
  | `toggle_cue_point` | Creates/removes cue point at current position | — |
207
214
 
208
- ### Memory (8) — Technique library persistence
215
+ ### Memory (showing 8 of 18) — Technique library persistence
209
216
 
210
217
  | Tool | What it does | Key params |
211
218
  |------|-------------|------------|
@@ -218,7 +225,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
218
225
  | `memory_update` | Updates name, tags, or qualities | `technique_id`, `name`, `tags`, `qualities` |
219
226
  | `memory_delete` | Removes technique (backs up first) | `technique_id` |
220
227
 
221
- ### Analyzer (38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
228
+ ### Analyzer (showing 20 of 38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
222
229
 
223
230
  | Tool | What it does | Key params |
224
231
  |------|-------------|------------|
@@ -243,7 +250,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
243
250
  | `stop_scrub` | Stop preview | `track_index`, `clip_index` |
244
251
  | `get_display_values` | Human-readable parameter values ("440 Hz", "-6 dB") | `track_index`, `device_index` |
245
252
 
246
- ### Automation (8) — Clip automation CRUD + intelligent curve generation
253
+ ### Automation (showing 8 of 9) — Clip automation CRUD + intelligent curve generation
247
254
 
248
255
  | Tool | What it does | Key params |
249
256
  |------|-------------|------------|