livepilot 1.25.0 → 1.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +9 -9
  3. package/installer/codex.js +87 -9
  4. package/livepilot/.Codex-plugin/plugin.json +8 -0
  5. package/livepilot/.claude-plugin/plugin.json +8 -0
  6. package/livepilot/.mcp.json +8 -0
  7. package/livepilot/agents/livepilot-producer/AGENT.md +314 -0
  8. package/livepilot/commands/arrange.md +47 -0
  9. package/livepilot/commands/beat.md +81 -0
  10. package/livepilot/commands/evaluate.md +49 -0
  11. package/livepilot/commands/memory.md +22 -0
  12. package/livepilot/commands/mix.md +47 -0
  13. package/livepilot/commands/perform.md +42 -0
  14. package/livepilot/commands/session.md +13 -0
  15. package/livepilot/commands/sounddesign.md +58 -0
  16. package/livepilot/rubrics/default_preset_check.md +82 -0
  17. package/livepilot/rubrics/layer_accumulation.md +79 -0
  18. package/livepilot/rubrics/layer_precision.md +79 -0
  19. package/livepilot/rubrics/modulation_presence.md +63 -0
  20. package/livepilot/rubrics/sound_design_depth.md +40 -0
  21. package/livepilot/skills/livepilot-arrangement/SKILL.md +164 -0
  22. package/livepilot/skills/livepilot-composition-engine/SKILL.md +151 -0
  23. package/livepilot/skills/livepilot-composition-engine/references/form-patterns.md +97 -0
  24. package/livepilot/skills/livepilot-composition-engine/references/transition-archetypes.md +102 -0
  25. package/livepilot/skills/livepilot-core/SKILL.md +261 -0
  26. package/livepilot/skills/livepilot-core/references/ableton-workflow-patterns.md +831 -0
  27. package/livepilot/skills/livepilot-core/references/affordances/_schema.md +160 -0
  28. package/livepilot/skills/livepilot-core/references/affordances/devices/auto-filter.yaml +133 -0
  29. package/livepilot/skills/livepilot-core/references/affordances/devices/chorus-ensemble.yaml +91 -0
  30. package/livepilot/skills/livepilot-core/references/affordances/devices/compressor.yaml +98 -0
  31. package/livepilot/skills/livepilot-core/references/affordances/devices/convolution-reverb.yaml +113 -0
  32. package/livepilot/skills/livepilot-core/references/affordances/devices/corpus.yaml +84 -0
  33. package/livepilot/skills/livepilot-core/references/affordances/devices/drift.yaml +105 -0
  34. package/livepilot/skills/livepilot-core/references/affordances/devices/echo.yaml +108 -0
  35. package/livepilot/skills/livepilot-core/references/affordances/devices/eq-eight.yaml +95 -0
  36. package/livepilot/skills/livepilot-core/references/affordances/devices/glue-compressor.yaml +88 -0
  37. package/livepilot/skills/livepilot-core/references/affordances/devices/granulator-iii.yaml +104 -0
  38. package/livepilot/skills/livepilot-core/references/affordances/devices/hybrid-reverb.yaml +83 -0
  39. package/livepilot/skills/livepilot-core/references/affordances/devices/operator.yaml +98 -0
  40. package/livepilot/skills/livepilot-core/references/affordances/devices/ping-pong-delay.yaml +104 -0
  41. package/livepilot/skills/livepilot-core/references/affordances/devices/poli.yaml +98 -0
  42. package/livepilot/skills/livepilot-core/references/affordances/devices/saturator.yaml +98 -0
  43. package/livepilot/skills/livepilot-core/references/affordances/devices/shifter.yaml +77 -0
  44. package/livepilot/skills/livepilot-core/references/affordances/devices/simpler.yaml +113 -0
  45. package/livepilot/skills/livepilot-core/references/affordances/devices/utility.yaml +95 -0
  46. package/livepilot/skills/livepilot-core/references/affordances/devices/vinyl-distortion.yaml +92 -0
  47. package/livepilot/skills/livepilot-core/references/affordances/devices/wavetable.yaml +98 -0
  48. package/livepilot/skills/livepilot-core/references/artist-vocabularies.md +389 -0
  49. package/livepilot/skills/livepilot-core/references/automation-atlas.md +272 -0
  50. package/livepilot/skills/livepilot-core/references/concepts/_schema.md +158 -0
  51. package/livepilot/skills/livepilot-core/references/concepts/artists/akufen.yaml +116 -0
  52. package/livepilot/skills/livepilot-core/references/concepts/artists/aphex-twin.yaml +133 -0
  53. package/livepilot/skills/livepilot-core/references/concepts/artists/arca-sophie.yaml +131 -0
  54. package/livepilot/skills/livepilot-core/references/concepts/artists/autechre.yaml +130 -0
  55. package/livepilot/skills/livepilot-core/references/concepts/artists/basic-channel.yaml +140 -0
  56. package/livepilot/skills/livepilot-core/references/concepts/artists/basinski.yaml +126 -0
  57. package/livepilot/skills/livepilot-core/references/concepts/artists/boards-of-canada.yaml +124 -0
  58. package/livepilot/skills/livepilot-core/references/concepts/artists/burial.yaml +127 -0
  59. package/livepilot/skills/livepilot-core/references/concepts/artists/com-truise-tycho.yaml +121 -0
  60. package/livepilot/skills/livepilot-core/references/concepts/artists/daft-punk.yaml +117 -0
  61. package/livepilot/skills/livepilot-core/references/concepts/artists/dj-premier-rza.yaml +119 -0
  62. package/livepilot/skills/livepilot-core/references/concepts/artists/gas.yaml +134 -0
  63. package/livepilot/skills/livepilot-core/references/concepts/artists/hawtin.yaml +127 -0
  64. package/livepilot/skills/livepilot-core/references/concepts/artists/isolee-luomo.yaml +130 -0
  65. package/livepilot/skills/livepilot-core/references/concepts/artists/j-dilla.yaml +133 -0
  66. package/livepilot/skills/livepilot-core/references/concepts/artists/jeff-mills.yaml +120 -0
  67. package/livepilot/skills/livepilot-core/references/concepts/artists/johannsson-richter.yaml +132 -0
  68. package/livepilot/skills/livepilot-core/references/concepts/artists/madlib.yaml +124 -0
  69. package/livepilot/skills/livepilot-core/references/concepts/artists/moodymann-theo-parrish.yaml +121 -0
  70. package/livepilot/skills/livepilot-core/references/concepts/artists/oneohtrix-point-never.yaml +126 -0
  71. package/livepilot/skills/livepilot-core/references/concepts/artists/photek-source-direct.yaml +120 -0
  72. package/livepilot/skills/livepilot-core/references/concepts/artists/rashad-spinn-traxman.yaml +122 -0
  73. package/livepilot/skills/livepilot-core/references/concepts/artists/robert-henke.yaml +113 -0
  74. package/livepilot/skills/livepilot-core/references/concepts/artists/shackleton.yaml +124 -0
  75. package/livepilot/skills/livepilot-core/references/concepts/artists/skream-mala.yaml +119 -0
  76. package/livepilot/skills/livepilot-core/references/concepts/artists/stars-of-the-lid.yaml +119 -0
  77. package/livepilot/skills/livepilot-core/references/concepts/artists/tim-hecker.yaml +122 -0
  78. package/livepilot/skills/livepilot-core/references/concepts/artists/villalobos.yaml +135 -0
  79. package/livepilot/skills/livepilot-core/references/concepts/genres/ambient.yaml +137 -0
  80. package/livepilot/skills/livepilot-core/references/concepts/genres/boom_bap.yaml +124 -0
  81. package/livepilot/skills/livepilot-core/references/concepts/genres/deep-minimal.yaml +130 -0
  82. package/livepilot/skills/livepilot-core/references/concepts/genres/deep_house.yaml +130 -0
  83. package/livepilot/skills/livepilot-core/references/concepts/genres/detroit_techno.yaml +116 -0
  84. package/livepilot/skills/livepilot-core/references/concepts/genres/disco.yaml +123 -0
  85. package/livepilot/skills/livepilot-core/references/concepts/genres/downtempo.yaml +129 -0
  86. package/livepilot/skills/livepilot-core/references/concepts/genres/drone.yaml +133 -0
  87. package/livepilot/skills/livepilot-core/references/concepts/genres/drum-and-bass.yaml +119 -0
  88. package/livepilot/skills/livepilot-core/references/concepts/genres/dub-techno.yaml +132 -0
  89. package/livepilot/skills/livepilot-core/references/concepts/genres/dub.yaml +129 -0
  90. package/livepilot/skills/livepilot-core/references/concepts/genres/dubstep.yaml +120 -0
  91. package/livepilot/skills/livepilot-core/references/concepts/genres/experimental.yaml +136 -0
  92. package/livepilot/skills/livepilot-core/references/concepts/genres/footwork.yaml +119 -0
  93. package/livepilot/skills/livepilot-core/references/concepts/genres/hip-hop.yaml +132 -0
  94. package/livepilot/skills/livepilot-core/references/concepts/genres/house.yaml +126 -0
  95. package/livepilot/skills/livepilot-core/references/concepts/genres/hyperpop.yaml +128 -0
  96. package/livepilot/skills/livepilot-core/references/concepts/genres/idm.yaml +134 -0
  97. package/livepilot/skills/livepilot-core/references/concepts/genres/lo_fi.yaml +129 -0
  98. package/livepilot/skills/livepilot-core/references/concepts/genres/microhouse.yaml +138 -0
  99. package/livepilot/skills/livepilot-core/references/concepts/genres/minimal-techno.yaml +116 -0
  100. package/livepilot/skills/livepilot-core/references/concepts/genres/modern-classical.yaml +123 -0
  101. package/livepilot/skills/livepilot-core/references/concepts/genres/soul.yaml +125 -0
  102. package/livepilot/skills/livepilot-core/references/concepts/genres/synthwave.yaml +123 -0
  103. package/livepilot/skills/livepilot-core/references/concepts/genres/techno.yaml +123 -0
  104. package/livepilot/skills/livepilot-core/references/concepts/genres/trap.yaml +120 -0
  105. package/livepilot/skills/livepilot-core/references/concepts/genres/uk-garage.yaml +121 -0
  106. package/livepilot/skills/livepilot-core/references/device-atlas/00-index.md +110 -0
  107. package/livepilot/skills/livepilot-core/references/device-atlas/distortion-and-character.md +687 -0
  108. package/livepilot/skills/livepilot-core/references/device-atlas/drums-and-percussion.md +753 -0
  109. package/livepilot/skills/livepilot-core/references/device-atlas/dynamics-and-punch.md +525 -0
  110. package/livepilot/skills/livepilot-core/references/device-atlas/eq-and-filtering.md +402 -0
  111. package/livepilot/skills/livepilot-core/references/device-atlas/midi-tools.md +963 -0
  112. package/livepilot/skills/livepilot-core/references/device-atlas/movement-and-modulation.md +874 -0
  113. package/livepilot/skills/livepilot-core/references/device-atlas/space-and-depth.md +571 -0
  114. package/livepilot/skills/livepilot-core/references/device-atlas/spectral-and-weird.md +714 -0
  115. package/livepilot/skills/livepilot-core/references/device-atlas/synths-native.md +953 -0
  116. package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +34 -0
  117. package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +204 -0
  118. package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +173 -0
  119. package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +211 -0
  120. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +188 -0
  121. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +162 -0
  122. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +229 -0
  123. package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +243 -0
  124. package/livepilot/skills/livepilot-core/references/genre-vocabularies.md +382 -0
  125. package/livepilot/skills/livepilot-core/references/m4l-devices.md +352 -0
  126. package/livepilot/skills/livepilot-core/references/memory-guide.md +178 -0
  127. package/livepilot/skills/livepilot-core/references/midi-recipes.md +402 -0
  128. package/livepilot/skills/livepilot-core/references/mixing-patterns.md +578 -0
  129. package/livepilot/skills/livepilot-core/references/overview.md +300 -0
  130. package/livepilot/skills/livepilot-core/references/pack-knowledge.md +319 -0
  131. package/livepilot/skills/livepilot-core/references/sample-manipulation.md +724 -0
  132. package/livepilot/skills/livepilot-core/references/sound-design-deep.md +140 -0
  133. package/livepilot/skills/livepilot-core/references/sound-design.md +393 -0
  134. package/livepilot/skills/livepilot-corpus-builder/SKILL.md +379 -0
  135. package/livepilot/skills/livepilot-creative-director/SKILL.md +455 -0
  136. package/livepilot/skills/livepilot-creative-director/references/anti-repetition-rules.md +214 -0
  137. package/livepilot/skills/livepilot-creative-director/references/creative-brief-template.md +222 -0
  138. package/livepilot/skills/livepilot-creative-director/references/hybrid-compilation.md +185 -0
  139. package/livepilot/skills/livepilot-creative-director/references/move-family-diversity-rule.md +258 -0
  140. package/livepilot/skills/livepilot-creative-director/references/phase-6-execution.md +409 -0
  141. package/livepilot/skills/livepilot-creative-director/references/the-four-move-rule.md +192 -0
  142. package/livepilot/skills/livepilot-devices/SKILL.md +213 -0
  143. package/livepilot/skills/livepilot-devices/references/load_browser_item-uri-grammar.md +82 -0
  144. package/livepilot/skills/livepilot-evaluation/SKILL.md +195 -0
  145. package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +176 -0
  146. package/livepilot/skills/livepilot-evaluation/references/evaluation-contracts.md +121 -0
  147. package/livepilot/skills/livepilot-evaluation/references/memory-promotion.md +110 -0
  148. package/livepilot/skills/livepilot-mix-engine/SKILL.md +136 -0
  149. package/livepilot/skills/livepilot-mix-engine/references/mix-critics.md +143 -0
  150. package/livepilot/skills/livepilot-mix-engine/references/mix-moves.md +105 -0
  151. package/livepilot/skills/livepilot-mixing/SKILL.md +157 -0
  152. package/livepilot/skills/livepilot-notes/SKILL.md +130 -0
  153. package/livepilot/skills/livepilot-performance-engine/SKILL.md +122 -0
  154. package/livepilot/skills/livepilot-performance-engine/references/performance-safety.md +98 -0
  155. package/livepilot/skills/livepilot-release/SKILL.md +151 -0
  156. package/livepilot/skills/livepilot-sample-engine/SKILL.md +117 -0
  157. package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +87 -0
  158. package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +51 -0
  159. package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +131 -0
  160. package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +225 -0
  161. package/livepilot/skills/livepilot-sound-design-engine/references/patch-model.md +119 -0
  162. package/livepilot/skills/livepilot-sound-design-engine/references/sound-design-critics.md +118 -0
  163. package/livepilot/skills/livepilot-wonder/SKILL.md +143 -0
  164. package/m4l_device/LivePilot_Analyzer.amxd +0 -0
  165. package/m4l_device/LivePilot_Elektron.amxd +0 -0
  166. package/m4l_device/LivePilot_Elektron.maxpat +758 -0
  167. package/m4l_device/livepilot_bridge.js +1 -1
  168. package/m4l_device/livepilot_elektron_bridge.js +82 -0
  169. package/mcp_server/__init__.py +1 -1
  170. package/mcp_server/atlas/tools.py +63 -12
  171. package/mcp_server/audit/checks.py +167 -6
  172. package/mcp_server/audit/state.py +88 -0
  173. package/mcp_server/audit/tools.py +6 -69
  174. package/mcp_server/composer/develop/apply.py +2 -2
  175. package/mcp_server/composer/full/apply.py +32 -6
  176. package/mcp_server/grader/__init__.py +17 -0
  177. package/mcp_server/grader/client.py +647 -0
  178. package/mcp_server/grader/iterator.py +57 -0
  179. package/mcp_server/grader/tools.py +263 -0
  180. package/mcp_server/m4l_bridge.py +5 -0
  181. package/mcp_server/runtime/execution_router.py +6 -0
  182. package/mcp_server/runtime/mcp_dispatch.py +18 -0
  183. package/mcp_server/runtime/remote_commands.py +2 -0
  184. package/mcp_server/server.py +12 -7
  185. package/mcp_server/tools/browser.py +68 -0
  186. package/package.json +20 -5
  187. package/remote_script/LivePilot/__init__.py +1 -1
  188. package/remote_script/LivePilot/server.py +63 -2
  189. package/requirements.txt +24 -3
  190. package/server.json +3 -3
@@ -0,0 +1,57 @@
1
+ """Revision-brief formatter.
2
+
3
+ Phase 1 — produces a markdown brief for the orchestrating agent (Claude Code
4
+ or composer planner) when a verdict fails. The agent is responsible for
5
+ deciding whether to retry; this module only formats the feedback.
6
+
7
+ Autonomous iteration loops land in Phase 2 once the rubric set is broader.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any
13
+
14
+
15
+ def format_revision_brief(verdict: dict[str, Any]) -> str:
16
+ """Markdown brief surfacing non-pass criteria.
17
+
18
+ Returns empty string only when there are zero `fail` and zero `warn`
19
+ criteria. A verdict can pass overall (no blocking failures) yet still
20
+ have advisory warnings worth surfacing — those produce an Advisory-only
21
+ brief.
22
+ """
23
+ failed = [c for c in verdict["criteria"] if c["severity"] == "fail"]
24
+ warns = [c for c in verdict["criteria"] if c["severity"] == "warn"]
25
+
26
+ if not failed and not warns:
27
+ return ""
28
+
29
+ headline = "needs revision" if failed else "review advisory items"
30
+ lines: list[str] = [
31
+ f"# Rubric `{verdict['rubric_id']}` — {headline}",
32
+ "",
33
+ ]
34
+
35
+ if failed:
36
+ lines.append("## Blocking failures")
37
+ for c in failed:
38
+ lines.append(f"### {c['id']}")
39
+ lines.append(f"- **summary:** {c['summary']}")
40
+ for issue in c["issues"]:
41
+ track = issue.get("track_index")
42
+ track_ref = f" (track {track})" if track is not None else ""
43
+ lines.append(f"- {issue['code']}{track_ref}: {issue['detail']}")
44
+ lines.append("")
45
+
46
+ if warns:
47
+ lines.append("## Advisory (non-blocking)")
48
+ for c in warns:
49
+ lines.append(f"### {c['id']}")
50
+ lines.append(f"- **summary:** {c['summary']}")
51
+ for issue in c["issues"]:
52
+ track = issue.get("track_index")
53
+ track_ref = f" (track {track})" if track is not None else ""
54
+ lines.append(f"- {issue['code']}{track_ref}: {issue['detail']}")
55
+ lines.append("")
56
+
57
+ return "\n".join(lines).rstrip() + "\n"
@@ -0,0 +1,263 @@
1
+ """Grader MCP tools — Phases 2c-α (light) + 2c-β (heavy).
2
+
3
+ Tools:
4
+ - `grader_list_rubrics()` — names of registered rubrics
5
+ - `grader_evaluate(rubric_id, heavy=False)` — fetches session state and
6
+ runs rubric. Light state covers `layer_accumulation`,
7
+ `default_preset_check`, plus the role+volume parts of every rubric.
8
+ Heavy state adds per-clip notes, per-clip automation, wavetable
9
+ mod-matrix, and session-level masking — required for `layer_precision`
10
+ to produce non-n/a verdicts on `sequence_per_track`,
11
+ `modulation_per_track`, and `masking_per_track`, and for
12
+ `modulation_presence` to leave the n/a state.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ import time
19
+ from typing import Any
20
+
21
+ from fastmcp import Context
22
+
23
+ from ..server import mcp
24
+ from ..audit.state import (
25
+ safe_call as _safe_call,
26
+ fetch_notes_for_clips as _fetch_notes_for_clips,
27
+ has_clip_automation as _has_clip_automation,
28
+ count_wavetable_routings as _count_wavetable_routings,
29
+ )
30
+ from . import client
31
+ from . import iterator
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ def _get_ableton(ctx: Context):
37
+ return ctx.lifespan_context["ableton"]
38
+
39
+
40
+ def _maybe_get_masking_report(ctx: Context) -> dict | None:
41
+ """Session-level masking report. Same pattern as audit_layer — calls
42
+ the mix_engine MCP tool's python function directly because masking
43
+ isn't a Remote Script command."""
44
+ try:
45
+ from ..mix_engine.tools import get_masking_report as _impl
46
+ return _impl(ctx) # type: ignore[arg-type]
47
+ except Exception as exc:
48
+ logger.debug("grader heavy: masking fetch failed: %s", exc)
49
+ return None
50
+
51
+
52
+ def _build_light_state(ctx: Context) -> dict[str, Any]:
53
+ """Light state — `get_session_info` + per-track `get_track_info`.
54
+
55
+ Sufficient for rubrics that only need track count, names, mixer,
56
+ devices. Skips per-clip and session-level heavy fetches.
57
+ """
58
+ ableton = _get_ableton(ctx)
59
+ session = _safe_call(ableton, "get_session_info") or {}
60
+ track_count = int(session.get("track_count") or 0)
61
+
62
+ tracks: list[dict[str, Any]] = []
63
+ for idx in range(track_count):
64
+ info = _safe_call(ableton, "get_track_info", {"track_index": idx})
65
+ if not info:
66
+ continue
67
+ if info.get("is_foldable") and info.get("is_master"):
68
+ continue
69
+ if info.get("is_return"):
70
+ continue
71
+ tracks.append({
72
+ "index": idx,
73
+ "name": info.get("name") or f"track_{idx}",
74
+ "mixer": info.get("mixer") or {},
75
+ "devices": info.get("devices") or [],
76
+ "clip_slots": info.get("clip_slots") or [],
77
+ })
78
+ return {"tracks": tracks, "fetched_at": time.time()}
79
+
80
+
81
+ def _build_heavy_state(ctx: Context, include_masking: bool = True) -> dict[str, Any]:
82
+ """Heavy state — light + per-clip notes + per-clip automation +
83
+ wavetable mod-matrix + (optionally) session-level masking report.
84
+
85
+ Cost: O(tracks × clips) for notes/automation. Realistic budget per
86
+ evaluation: 5–15s on a 4-track session, 30–60s on a populated arrangement.
87
+ """
88
+ ableton = _get_ableton(ctx)
89
+ state = _build_light_state(ctx)
90
+ for t in state["tracks"]:
91
+ idx = t["index"]
92
+ clip_slots = t.get("clip_slots") or []
93
+ t["notes_per_clip"] = _fetch_notes_for_clips(ableton, idx, clip_slots)
94
+ t["has_clip_automation"] = _has_clip_automation(ableton, idx, clip_slots)
95
+ t["wavetable_mod_routings"] = _count_wavetable_routings(ableton, idx, t.get("devices") or [])
96
+
97
+ if include_masking:
98
+ masking_report = _maybe_get_masking_report(ctx)
99
+ if masking_report:
100
+ state["masking_report"] = masking_report
101
+
102
+ state["heavy"] = True
103
+ return state
104
+
105
+
106
+ @mcp.tool()
107
+ def grader_list_rubrics(ctx: Context) -> dict:
108
+ """List the rubrics the grader can evaluate.
109
+
110
+ Returns the rubric names registered in `mcp_server.grader.client`. Each
111
+ rubric corresponds to a binding rule from CLAUDE.md (§7.3, §1, §4, §5,
112
+ §2). See `livepilot/rubrics/<rubric_id>.md` for criteria detail.
113
+ """
114
+ return {
115
+ "rubrics": client.list_rubrics(),
116
+ "light_state_sufficient": [
117
+ "layer_accumulation",
118
+ "default_preset_check",
119
+ ],
120
+ "heavy_state_recommended": [
121
+ "modulation_presence",
122
+ "layer_precision",
123
+ "sound_design_depth",
124
+ ],
125
+ }
126
+
127
+
128
+ @mcp.tool()
129
+ def grader_evaluate(
130
+ ctx: Context,
131
+ rubric_id: str,
132
+ heavy: bool = False,
133
+ include_brief: bool = True,
134
+ include_masking: bool = True,
135
+ ) -> dict:
136
+ """Run a rubric across the current session, return verdict + brief.
137
+
138
+ State modes:
139
+ - heavy=False (default): `get_session_info` + per-track
140
+ `get_track_info`. ~3s on a 4-track session. Sufficient for
141
+ `layer_accumulation` and `default_preset_check`.
142
+ - heavy=True: adds per-clip `get_notes`, per-clip
143
+ `get_clip_automation`, per-Wavetable `get_wavetable_mod_matrix`,
144
+ and (when `include_masking=True`) session-level
145
+ `get_masking_report`. Required for `layer_precision` to produce
146
+ non-n/a verdicts on sequence/modulation/masking criteria, and
147
+ for `modulation_presence` to leave n/a.
148
+
149
+ Args:
150
+ rubric_id: Name of a registered rubric (see `grader_list_rubrics`).
151
+ heavy: When True, fetch per-clip + session-level signals. Slower
152
+ but needed for §4/§5 criteria beyond `stereo_per_track`.
153
+ include_brief: When True (default), attaches a markdown revision
154
+ brief formatted for an orchestrating agent.
155
+ include_masking: When True (default; only relevant when heavy=True),
156
+ includes the session-level masking report. Adds ~200–600ms.
157
+
158
+ Returns:
159
+ {
160
+ "rubric_id": str,
161
+ "passed": bool,
162
+ "criteria": [{id, severity, summary, issues, evidence}, ...],
163
+ "revision_brief": str, # present when include_brief=True
164
+ "track_count_audited": int,
165
+ "state_mode": "light" | "heavy",
166
+ "elapsed_ms": int,
167
+ }
168
+ """
169
+ started = time.time()
170
+
171
+ if rubric_id not in client.list_rubrics():
172
+ return {
173
+ "error": f"unknown rubric_id '{rubric_id}'",
174
+ "available": client.list_rubrics(),
175
+ }
176
+
177
+ state = _build_heavy_state(ctx, include_masking=include_masking) if heavy else _build_light_state(ctx)
178
+ verdict = client.evaluate(rubric_id, state)
179
+
180
+ elapsed_ms = int((time.time() - started) * 1000)
181
+ response = {
182
+ **verdict,
183
+ "track_count_audited": len(state["tracks"]),
184
+ "state_mode": "heavy" if heavy else "light",
185
+ "elapsed_ms": elapsed_ms,
186
+ }
187
+ if include_brief:
188
+ response["revision_brief"] = iterator.format_revision_brief(verdict)
189
+ return response
190
+
191
+
192
+ @mcp.tool()
193
+ def grader_evaluate_all(
194
+ ctx: Context,
195
+ heavy: bool = True,
196
+ include_brief: bool = True,
197
+ include_masking: bool = True,
198
+ ) -> dict:
199
+ """Run ALL rubrics against the current session in one call.
200
+
201
+ Builds session state once and evaluates every registered rubric
202
+ against it. ~5× cheaper than calling `grader_evaluate` per rubric
203
+ because state-fetching is the dominant cost.
204
+
205
+ Default `heavy=True` — assumes a full audit. Pass `heavy=False`
206
+ for a fast §1/§7.3-only sweep.
207
+
208
+ Args:
209
+ heavy: When True (default), uses heavy state. When False, only
210
+ §1 default_preset_check and §7.3 layer_accumulation produce
211
+ useful verdicts; the others return n/a.
212
+ include_brief: Attach per-rubric revision_brief markdown.
213
+ include_masking: Include session-level masking report (heavy only).
214
+
215
+ Returns:
216
+ {
217
+ "rubrics": {
218
+ "<rubric_id>": {<verdict + brief>},
219
+ ...
220
+ },
221
+ "any_failed": bool, # True if any rubric verdict is fail
222
+ "any_advisory": bool, # True if any rubric has warns
223
+ "track_count_audited": int,
224
+ "state_mode": "light" | "heavy",
225
+ "elapsed_ms": int,
226
+ "combined_brief": str, # merged across rubrics
227
+ }
228
+ """
229
+ started = time.time()
230
+ state = _build_heavy_state(ctx, include_masking=include_masking) if heavy else _build_light_state(ctx)
231
+
232
+ results: dict[str, Any] = {}
233
+ any_failed = False
234
+ any_advisory = False
235
+ brief_parts: list[str] = []
236
+
237
+ for rubric_id in client.list_rubrics():
238
+ verdict = client.evaluate(rubric_id, state)
239
+ if not verdict["passed"]:
240
+ any_failed = True
241
+ if any(c["severity"] == "warn" for c in verdict["criteria"]):
242
+ any_advisory = True
243
+
244
+ entry: dict[str, Any] = dict(verdict)
245
+ if include_brief:
246
+ brief = iterator.format_revision_brief(verdict)
247
+ entry["revision_brief"] = brief
248
+ if brief:
249
+ brief_parts.append(brief)
250
+ results[rubric_id] = entry
251
+
252
+ elapsed_ms = int((time.time() - started) * 1000)
253
+ response: dict[str, Any] = {
254
+ "rubrics": results,
255
+ "any_failed": any_failed,
256
+ "any_advisory": any_advisory,
257
+ "track_count_audited": len(state["tracks"]),
258
+ "state_mode": "heavy" if heavy else "light",
259
+ "elapsed_ms": elapsed_ms,
260
+ }
261
+ if include_brief:
262
+ response["combined_brief"] = "\n\n---\n\n".join(brief_parts) if brief_parts else ""
263
+ return response
@@ -1014,6 +1014,11 @@ class M4LBridge:
1014
1014
  while len(s_bytes) % 4 != 0:
1015
1015
  s_bytes += b'\x00'
1016
1016
  arg_data += s_bytes
1017
+ else:
1018
+ raise TypeError(
1019
+ "OSC argument for %s must be int, float, or str, got %s"
1020
+ % (address, type(arg).__name__)
1021
+ )
1017
1022
 
1018
1023
  tag_bytes = type_tags.encode('ascii') + b'\x00'
1019
1024
  while len(tag_bytes) % 4 != 0:
@@ -36,7 +36,10 @@ from .remote_commands import BRIDGE_COMMANDS, REMOTE_COMMANDS
36
36
  MCP_TOOLS: frozenset[str] = frozenset({
37
37
  "apply_automation_shape",
38
38
  "apply_gesture_template",
39
+ "analyze_sample",
40
+ "analyze_synth_patch",
39
41
  "analyze_mix",
42
+ "get_masking_report",
40
43
  "get_master_spectrum",
41
44
  "get_emotional_arc",
42
45
  "get_motif_graph",
@@ -92,7 +95,10 @@ READ_ONLY_TOOLS: frozenset[str] = frozenset({
92
95
  "get_cue_points",
93
96
  "get_rack_chains",
94
97
  "get_clip_automation",
98
+ "analyze_sample",
99
+ "analyze_synth_patch",
95
100
  "analyze_mix",
101
+ "get_masking_report",
96
102
  "get_emotional_arc",
97
103
  "get_motif_graph",
98
104
  "get_session_diagnostics",
@@ -60,11 +60,26 @@ async def _apply_gesture_template(params: dict, ctx: Any = None) -> dict:
60
60
  return await _call(apply_gesture_template, ctx, params)
61
61
 
62
62
 
63
+ async def _analyze_sample(params: dict, ctx: Any = None) -> dict:
64
+ from ..sample_engine.tools import analyze_sample
65
+ return await _call(analyze_sample, ctx, params)
66
+
67
+
68
+ async def _analyze_synth_patch(params: dict, ctx: Any = None) -> dict:
69
+ from ..synthesis_brain.tools import analyze_synth_patch
70
+ return await _call(analyze_synth_patch, ctx, params)
71
+
72
+
63
73
  async def _analyze_mix(params: dict, ctx: Any = None) -> dict:
64
74
  from ..mix_engine.tools import analyze_mix
65
75
  return await _call(analyze_mix, ctx, params)
66
76
 
67
77
 
78
+ async def _get_masking_report(params: dict, ctx: Any = None) -> dict:
79
+ from ..mix_engine.tools import get_masking_report
80
+ return await _call(get_masking_report, ctx, params)
81
+
82
+
68
83
  async def _get_master_spectrum(params: dict, ctx: Any = None) -> dict:
69
84
  from ..tools.analyzer import get_master_spectrum
70
85
  return await _call(get_master_spectrum, ctx, params)
@@ -151,7 +166,10 @@ def build_mcp_dispatch_registry() -> dict[str, Callable]:
151
166
  "load_sample_to_simpler": _load_sample_to_simpler,
152
167
  "apply_automation_shape": _apply_automation_shape,
153
168
  "apply_gesture_template": _apply_gesture_template,
169
+ "analyze_sample": _analyze_sample,
170
+ "analyze_synth_patch": _analyze_synth_patch,
154
171
  "analyze_mix": _analyze_mix,
172
+ "get_masking_report": _get_masking_report,
155
173
  "get_master_spectrum": _get_master_spectrum,
156
174
  "get_emotional_arc": _get_emotional_arc,
157
175
  "get_motif_graph": _get_motif_graph,
@@ -83,6 +83,8 @@ REMOTE_COMMANDS: frozenset[str] = frozenset({
83
83
  "capture_midi", "start_recording", "stop_recording",
84
84
  "get_cue_points", "jump_to_cue", "toggle_cue_point",
85
85
  "back_to_arranger", "force_arrangement",
86
+ "arrangement_automation_via_session_record_start",
87
+ "arrangement_automation_via_session_record_complete",
86
88
  # scales — Song + per-clip scale awareness (Live 12.0+)
87
89
  "get_song_scale", "set_song_scale", "set_song_scale_mode",
88
90
  "list_available_scales",
@@ -309,6 +309,7 @@ from .composer import tools as composer_tools # noqa: F401, E40
309
309
  from .synthesis_brain import tools as synthesis_brain_tools # noqa: F401, E402
310
310
  from .user_corpus import tools as user_corpus_tools # noqa: F401, E402
311
311
  from .audit import tools as audit_tools # noqa: F401, E402
312
+ from .grader import tools as grader_tools # noqa: F401, E402
312
313
  from .tools import diagnostics # noqa: F401, E402
313
314
  from .tools import miditool # noqa: F401, E402
314
315
 
@@ -354,14 +355,14 @@ def _coerce_schema_property(prop: dict) -> None:
354
355
  def _get_all_tools():
355
356
  """Get all registered tools — defends against FastMCP internal drift.
356
357
 
357
- FastMCP's public API doesn't expose the registry as of 3.2.x (see
358
+ FastMCP's public API doesn't expose the registry as of 3.3.x (see
358
359
  docs/FASTMCP_UPSTREAM_FR.md). Until it does, we probe known internal
359
360
  attribute paths. Each probe fires in try/except so a structural
360
- rearrangement (e.g. ``_components`` renamed under 3.3+) falls through
361
+ rearrangement (e.g. ``_components`` renamed under 3.4+) falls through
361
362
  to the next path rather than exploding.
362
363
 
363
364
  WARNING: Accesses FastMCP private internals. Pinned to
364
- fastmcp>=3.0.0,<3.3.0 in requirements.txt. The startup self-test
365
+ fastmcp>=3.3.1,<3.4.0 in requirements.txt. The startup self-test
365
366
  (_assert_tool_registry_accessible) will fail loudly if every probe
366
367
  returns empty — better than silently returning [] and disabling
367
368
  schema coercion.
@@ -369,14 +370,18 @@ def _get_all_tools():
369
370
  probes = [
370
371
  # FastMCP 0.x: mcp._tool_manager._tools (dict of name -> Tool)
371
372
  ("_tool_manager._tools", lambda: list(mcp._tool_manager._tools.values())),
372
- # FastMCP 3.0–3.2: mcp._local_provider._components
373
+ # FastMCP 3.0–3.3: mcp._local_provider._components
374
+ # (verified 2026-05-21 against fastmcp 3.3.1 — still the active path)
373
375
  (
374
376
  "_local_provider._components",
375
377
  lambda: list(mcp._local_provider._components.values()),
376
378
  ),
377
- # FastMCP 3.3+ speculative: mcp._local_provider._tools (anticipated
378
- # rename based on naming conventions in other providers). Kept here
379
- # so a future bump surfaces a partial match rather than a full miss.
379
+ # FastMCP 3.4+ speculative: mcp._local_provider._tools (anticipated
380
+ # rename based on naming conventions in other providers). Verified
381
+ # 2026-05-21 against fastmcp 3.3.1 the rename did NOT happen in
382
+ # 3.3.x; ``_local_provider._components`` remains the live registry.
383
+ # Kept here so a future bump that DOES rename surfaces a partial
384
+ # match rather than a full miss.
380
385
  (
381
386
  "_local_provider._tools",
382
387
  lambda: list(mcp._local_provider._tools.values()),
@@ -30,6 +30,64 @@ def _validate_track_index(track_index: int):
30
30
  )
31
31
 
32
32
 
33
+ def _atlas_preflight_for_load(device_name: str) -> Optional[dict]:
34
+ """Atlas-aware preflight check for a freshly-loaded device.
35
+
36
+ Returns a dict with `self_contained: false` warning when the loaded
37
+ device is in the enriched atlas AND declares it requires a source
38
+ sample / capture. Returns None for self-contained devices, devices
39
+ not in the atlas, or atlas lookup failures.
40
+
41
+ Added 2026-05-08 after a Granulator III load silently produced no
42
+ audio: instrument loaded fine, grain params programmed, BUT no sample
43
+ in the source slot → silence. The atlas YAML for Granulator III has
44
+ `self_contained: false` and signature_techniques all start with "Load
45
+ a sample → ..." but neither was surfaced at load time. This preflight
46
+ closes that gap by reading the atlas immediately after load and
47
+ surfacing the requirement in the load response.
48
+ """
49
+ if not device_name:
50
+ return None
51
+ try:
52
+ from ..atlas import get_atlas
53
+ atlas = get_atlas()
54
+ except Exception:
55
+ return None
56
+ if atlas is None:
57
+ return None
58
+ try:
59
+ entry = atlas.lookup(device_name)
60
+ except Exception:
61
+ return None
62
+ if not entry or not entry.get("enriched"):
63
+ return None
64
+ if entry.get("self_contained") is not False:
65
+ return None # self-contained or unspecified — no warning needed
66
+
67
+ techniques = entry.get("signature_techniques") or []
68
+ first_hint = ""
69
+ if techniques and isinstance(techniques[0], dict):
70
+ first_hint = (
71
+ techniques[0].get("description")
72
+ or techniques[0].get("name")
73
+ or ""
74
+ )
75
+
76
+ return {
77
+ "self_contained": False,
78
+ "device_id": entry.get("id"),
79
+ "warning": (
80
+ f"{device_name} is not self-contained — it requires a source "
81
+ "sample or real-time audio capture to produce sound. The "
82
+ "instrument is loaded but will be silent until a sample is "
83
+ "added. Either drag audio onto its waveform display, OR load "
84
+ "a Sounds preset chain via search_browser(path='sounds', "
85
+ f"name_filter='{device_name}') that ships with a sample baked in."
86
+ ),
87
+ "first_technique_hint": str(first_hint).strip()[:240],
88
+ }
89
+
90
+
33
91
  @mcp.tool()
34
92
  def get_browser_tree(ctx: Context, category_type: str = "all") -> dict:
35
93
  """Get an overview of browser categories and their children."""
@@ -297,6 +355,16 @@ def load_browser_item(
297
355
  except Exception:
298
356
  pass
299
357
 
358
+ # Layer 0 — atlas-aware preflight. Surface a follow-up hint when the
359
+ # loaded device declares self_contained=false in its atlas enrichment
360
+ # YAML (granular samplers, sample players). Prevents the silent-
361
+ # Granulator-III failure mode where the instrument loads, params get
362
+ # programmed, but no audio source has been added.
363
+ if device_name_loaded:
364
+ preflight = _atlas_preflight_for_load(device_name_loaded)
365
+ if preflight is not None:
366
+ result["atlas_preflight"] = preflight
367
+
300
368
  # Layer 1 — Simpler role-aware defaults
301
369
  if role and device_index_resolved is not None and "Simpler" in device_class:
302
370
  applied = []
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.25.0",
3
+ "version": "1.26.1",
4
4
  "mcpName": "io.github.dreamrec/livepilot",
5
- "description": "Agentic production system for Ableton Live 12 \u2014 462 tools, 55 domains, 44 semantic moves. Device atlas (5264 devices, 120 enriched, 7 indexes), Splice intelligence (gRPC + GraphQL describe-a-sound + preview + collections + presets), 9-band spectral perception auto-loaded via ensure_analyzer_on_master, Creative Director skill, technique memory, 12 creative intelligence engines",
5
+ "description": "Agentic production system for Ableton Live 12 465 tools, 56 domains, 44 semantic moves. Device atlas (5264 devices, 120 enriched, 7 indexes), Splice intelligence (gRPC + GraphQL describe-a-sound + preview + collections + presets), 9-band spectral perception auto-loaded via ensure_analyzer_on_master, Creative Director skill, technique memory, 12 creative intelligence engines",
6
6
  "author": "Pilot Studio",
7
7
  "license": "BSL-1.1",
8
8
  "type": "commonjs",
9
9
  "bin": {
10
- "livepilot": "./bin/livepilot.js"
10
+ "livepilot": "bin/livepilot.js"
11
11
  },
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "https://github.com/dreamrec/LivePilot"
14
+ "url": "git+https://github.com/dreamrec/LivePilot.git"
15
15
  },
16
16
  "homepage": "https://github.com/dreamrec/LivePilot",
17
17
  "bugs": {
@@ -47,6 +47,7 @@
47
47
  "files": [
48
48
  "bin/**/*.js",
49
49
  "installer/**/*.js",
50
+ "livepilot/**",
50
51
  "mcp_server/**/*.py",
51
52
  "mcp_server/**/*.json",
52
53
  "mcp_server/**/*.yaml",
@@ -56,6 +57,9 @@
56
57
  "m4l_device/LivePilot_Analyzer.amxd",
57
58
  "m4l_device/LivePilot_Analyzer.adv",
58
59
  "m4l_device/livepilot_bridge.js",
60
+ "m4l_device/LivePilot_Elektron.amxd",
61
+ "m4l_device/LivePilot_Elektron.maxpat",
62
+ "m4l_device/livepilot_elektron_bridge.js",
59
63
  "m4l_device/BUILD_GUIDE.md",
60
64
  "requirements.txt",
61
65
  "README.md",
@@ -64,6 +68,17 @@
64
68
  "server.json",
65
69
  "!**/__pycache__/**",
66
70
  "!**/*.pyc",
67
- "!**/.DS_Store"
71
+ "!**/.DS_Store",
72
+ "!livepilot/skills/livepilot-core/references/device-atlas/synths-m4l.md",
73
+ "!livepilot/skills/livepilot-core/references/device-atlas/plugins-synths.md",
74
+ "!livepilot/skills/livepilot-core/references/device-atlas/utility-and-workflow.md",
75
+ "!livepilot/skills/livepilot-core/references/device-atlas/samples-and-irs.md",
76
+ "!livepilot/skills/livepilot-core/references/device-atlas/presets-by-vibe.md",
77
+ "!livepilot/skills/livepilot-devices/references/m4l-vendor/**",
78
+ "!livepilot/skills/livepilot-devices/references/m4l-depth-pass-findings.md",
79
+ "!livepilot/skills/livepilot-devices/references/m4l-depth-pass-resume.md",
80
+ "!livepilot/skills/livepilot-devices/references/m4l-library-deep.md",
81
+ "!livepilot/skills/livepilot-devices/references/m4l-master-reference.md",
82
+ "!livepilot/skills/livepilot-devices/references/m4l-technique-map.md"
68
83
  ]
69
84
  }
@@ -5,7 +5,7 @@ Entry point for the ControlSurface. Ableton calls create_instance(c_instance)
5
5
  when this script is selected in Preferences > Link, Tempo & MIDI.
6
6
  """
7
7
 
8
- __version__ = "1.25.0"
8
+ __version__ = "1.26.1"
9
9
 
10
10
  from _Framework.ControlSurface import ControlSurface
11
11
  from . import router