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.
- package/CHANGELOG.md +80 -0
- package/README.md +9 -9
- package/installer/codex.js +87 -9
- package/livepilot/.Codex-plugin/plugin.json +8 -0
- package/livepilot/.claude-plugin/plugin.json +8 -0
- package/livepilot/.mcp.json +8 -0
- package/livepilot/agents/livepilot-producer/AGENT.md +314 -0
- package/livepilot/commands/arrange.md +47 -0
- package/livepilot/commands/beat.md +81 -0
- package/livepilot/commands/evaluate.md +49 -0
- package/livepilot/commands/memory.md +22 -0
- package/livepilot/commands/mix.md +47 -0
- package/livepilot/commands/perform.md +42 -0
- package/livepilot/commands/session.md +13 -0
- package/livepilot/commands/sounddesign.md +58 -0
- package/livepilot/rubrics/default_preset_check.md +82 -0
- package/livepilot/rubrics/layer_accumulation.md +79 -0
- package/livepilot/rubrics/layer_precision.md +79 -0
- package/livepilot/rubrics/modulation_presence.md +63 -0
- package/livepilot/rubrics/sound_design_depth.md +40 -0
- package/livepilot/skills/livepilot-arrangement/SKILL.md +164 -0
- package/livepilot/skills/livepilot-composition-engine/SKILL.md +151 -0
- package/livepilot/skills/livepilot-composition-engine/references/form-patterns.md +97 -0
- package/livepilot/skills/livepilot-composition-engine/references/transition-archetypes.md +102 -0
- package/livepilot/skills/livepilot-core/SKILL.md +261 -0
- package/livepilot/skills/livepilot-core/references/ableton-workflow-patterns.md +831 -0
- package/livepilot/skills/livepilot-core/references/affordances/_schema.md +160 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/auto-filter.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/chorus-ensemble.yaml +91 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/compressor.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/convolution-reverb.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/corpus.yaml +84 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/drift.yaml +105 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/echo.yaml +108 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/eq-eight.yaml +95 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/glue-compressor.yaml +88 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/granulator-iii.yaml +104 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/hybrid-reverb.yaml +83 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/operator.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/ping-pong-delay.yaml +104 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/poli.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/saturator.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/shifter.yaml +77 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/simpler.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/utility.yaml +95 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/vinyl-distortion.yaml +92 -0
- package/livepilot/skills/livepilot-core/references/affordances/devices/wavetable.yaml +98 -0
- package/livepilot/skills/livepilot-core/references/artist-vocabularies.md +389 -0
- package/livepilot/skills/livepilot-core/references/automation-atlas.md +272 -0
- package/livepilot/skills/livepilot-core/references/concepts/_schema.md +158 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/akufen.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/aphex-twin.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/arca-sophie.yaml +131 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/autechre.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/basic-channel.yaml +140 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/basinski.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/boards-of-canada.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/burial.yaml +127 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/com-truise-tycho.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/daft-punk.yaml +117 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/dj-premier-rza.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/gas.yaml +134 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/hawtin.yaml +127 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/isolee-luomo.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/j-dilla.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/jeff-mills.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/johannsson-richter.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/madlib.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/moodymann-theo-parrish.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/oneohtrix-point-never.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/photek-source-direct.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/rashad-spinn-traxman.yaml +122 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/robert-henke.yaml +113 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/shackleton.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/skream-mala.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/stars-of-the-lid.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/tim-hecker.yaml +122 -0
- package/livepilot/skills/livepilot-core/references/concepts/artists/villalobos.yaml +135 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/ambient.yaml +137 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/boom_bap.yaml +124 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/deep-minimal.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/deep_house.yaml +130 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/detroit_techno.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/disco.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/downtempo.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/drone.yaml +133 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/drum-and-bass.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dub-techno.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dub.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/dubstep.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/experimental.yaml +136 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/footwork.yaml +119 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/hip-hop.yaml +132 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/house.yaml +126 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/hyperpop.yaml +128 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/idm.yaml +134 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/lo_fi.yaml +129 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/microhouse.yaml +138 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/minimal-techno.yaml +116 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/modern-classical.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/soul.yaml +125 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/synthwave.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/techno.yaml +123 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/trap.yaml +120 -0
- package/livepilot/skills/livepilot-core/references/concepts/genres/uk-garage.yaml +121 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/00-index.md +110 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/distortion-and-character.md +687 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/drums-and-percussion.md +753 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/dynamics-and-punch.md +525 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/eq-and-filtering.md +402 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/midi-tools.md +963 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/movement-and-modulation.md +874 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/space-and-depth.md +571 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/spectral-and-weird.md +714 -0
- package/livepilot/skills/livepilot-core/references/device-atlas/synths-native.md +953 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +34 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +204 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +173 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +211 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +188 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +162 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +229 -0
- package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +243 -0
- package/livepilot/skills/livepilot-core/references/genre-vocabularies.md +382 -0
- package/livepilot/skills/livepilot-core/references/m4l-devices.md +352 -0
- package/livepilot/skills/livepilot-core/references/memory-guide.md +178 -0
- package/livepilot/skills/livepilot-core/references/midi-recipes.md +402 -0
- package/livepilot/skills/livepilot-core/references/mixing-patterns.md +578 -0
- package/livepilot/skills/livepilot-core/references/overview.md +300 -0
- package/livepilot/skills/livepilot-core/references/pack-knowledge.md +319 -0
- package/livepilot/skills/livepilot-core/references/sample-manipulation.md +724 -0
- package/livepilot/skills/livepilot-core/references/sound-design-deep.md +140 -0
- package/livepilot/skills/livepilot-core/references/sound-design.md +393 -0
- package/livepilot/skills/livepilot-corpus-builder/SKILL.md +379 -0
- package/livepilot/skills/livepilot-creative-director/SKILL.md +455 -0
- package/livepilot/skills/livepilot-creative-director/references/anti-repetition-rules.md +214 -0
- package/livepilot/skills/livepilot-creative-director/references/creative-brief-template.md +222 -0
- package/livepilot/skills/livepilot-creative-director/references/hybrid-compilation.md +185 -0
- package/livepilot/skills/livepilot-creative-director/references/move-family-diversity-rule.md +258 -0
- package/livepilot/skills/livepilot-creative-director/references/phase-6-execution.md +409 -0
- package/livepilot/skills/livepilot-creative-director/references/the-four-move-rule.md +192 -0
- package/livepilot/skills/livepilot-devices/SKILL.md +213 -0
- package/livepilot/skills/livepilot-devices/references/load_browser_item-uri-grammar.md +82 -0
- package/livepilot/skills/livepilot-evaluation/SKILL.md +195 -0
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +176 -0
- package/livepilot/skills/livepilot-evaluation/references/evaluation-contracts.md +121 -0
- package/livepilot/skills/livepilot-evaluation/references/memory-promotion.md +110 -0
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +136 -0
- package/livepilot/skills/livepilot-mix-engine/references/mix-critics.md +143 -0
- package/livepilot/skills/livepilot-mix-engine/references/mix-moves.md +105 -0
- package/livepilot/skills/livepilot-mixing/SKILL.md +157 -0
- package/livepilot/skills/livepilot-notes/SKILL.md +130 -0
- package/livepilot/skills/livepilot-performance-engine/SKILL.md +122 -0
- package/livepilot/skills/livepilot-performance-engine/references/performance-safety.md +98 -0
- package/livepilot/skills/livepilot-release/SKILL.md +151 -0
- package/livepilot/skills/livepilot-sample-engine/SKILL.md +117 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +87 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +51 -0
- package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +131 -0
- package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +225 -0
- package/livepilot/skills/livepilot-sound-design-engine/references/patch-model.md +119 -0
- package/livepilot/skills/livepilot-sound-design-engine/references/sound-design-critics.md +118 -0
- package/livepilot/skills/livepilot-wonder/SKILL.md +143 -0
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/LivePilot_Elektron.amxd +0 -0
- package/m4l_device/LivePilot_Elektron.maxpat +758 -0
- package/m4l_device/livepilot_bridge.js +1 -1
- package/m4l_device/livepilot_elektron_bridge.js +82 -0
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/tools.py +63 -12
- package/mcp_server/audit/checks.py +167 -6
- package/mcp_server/audit/state.py +88 -0
- package/mcp_server/audit/tools.py +6 -69
- package/mcp_server/composer/develop/apply.py +2 -2
- package/mcp_server/composer/full/apply.py +32 -6
- package/mcp_server/grader/__init__.py +17 -0
- package/mcp_server/grader/client.py +647 -0
- package/mcp_server/grader/iterator.py +57 -0
- package/mcp_server/grader/tools.py +263 -0
- package/mcp_server/m4l_bridge.py +5 -0
- package/mcp_server/runtime/execution_router.py +6 -0
- package/mcp_server/runtime/mcp_dispatch.py +18 -0
- package/mcp_server/runtime/remote_commands.py +2 -0
- package/mcp_server/server.py +12 -7
- package/mcp_server/tools/browser.py +68 -0
- package/package.json +20 -5
- package/remote_script/LivePilot/__init__.py +1 -1
- package/remote_script/LivePilot/server.py +63 -2
- package/requirements.txt +24 -3
- 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
|
package/mcp_server/m4l_bridge.py
CHANGED
|
@@ -1014,6 +1014,11 @@ class M4LBridge:
|
|
|
1014
1014
|
while len(s_bytes) % 4 != 0:
|
|
1015
1015
|
s_bytes += b'\x00'
|
|
1016
1016
|
arg_data += s_bytes
|
|
1017
|
+
else:
|
|
1018
|
+
raise TypeError(
|
|
1019
|
+
"OSC argument for %s must be int, float, or str, got %s"
|
|
1020
|
+
% (address, type(arg).__name__)
|
|
1021
|
+
)
|
|
1017
1022
|
|
|
1018
1023
|
tag_bytes = type_tags.encode('ascii') + b'\x00'
|
|
1019
1024
|
while len(tag_bytes) % 4 != 0:
|
|
@@ -36,7 +36,10 @@ from .remote_commands import BRIDGE_COMMANDS, REMOTE_COMMANDS
|
|
|
36
36
|
MCP_TOOLS: frozenset[str] = frozenset({
|
|
37
37
|
"apply_automation_shape",
|
|
38
38
|
"apply_gesture_template",
|
|
39
|
+
"analyze_sample",
|
|
40
|
+
"analyze_synth_patch",
|
|
39
41
|
"analyze_mix",
|
|
42
|
+
"get_masking_report",
|
|
40
43
|
"get_master_spectrum",
|
|
41
44
|
"get_emotional_arc",
|
|
42
45
|
"get_motif_graph",
|
|
@@ -92,7 +95,10 @@ READ_ONLY_TOOLS: frozenset[str] = frozenset({
|
|
|
92
95
|
"get_cue_points",
|
|
93
96
|
"get_rack_chains",
|
|
94
97
|
"get_clip_automation",
|
|
98
|
+
"analyze_sample",
|
|
99
|
+
"analyze_synth_patch",
|
|
95
100
|
"analyze_mix",
|
|
101
|
+
"get_masking_report",
|
|
96
102
|
"get_emotional_arc",
|
|
97
103
|
"get_motif_graph",
|
|
98
104
|
"get_session_diagnostics",
|
|
@@ -60,11 +60,26 @@ async def _apply_gesture_template(params: dict, ctx: Any = None) -> dict:
|
|
|
60
60
|
return await _call(apply_gesture_template, ctx, params)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
async def _analyze_sample(params: dict, ctx: Any = None) -> dict:
|
|
64
|
+
from ..sample_engine.tools import analyze_sample
|
|
65
|
+
return await _call(analyze_sample, ctx, params)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
async def _analyze_synth_patch(params: dict, ctx: Any = None) -> dict:
|
|
69
|
+
from ..synthesis_brain.tools import analyze_synth_patch
|
|
70
|
+
return await _call(analyze_synth_patch, ctx, params)
|
|
71
|
+
|
|
72
|
+
|
|
63
73
|
async def _analyze_mix(params: dict, ctx: Any = None) -> dict:
|
|
64
74
|
from ..mix_engine.tools import analyze_mix
|
|
65
75
|
return await _call(analyze_mix, ctx, params)
|
|
66
76
|
|
|
67
77
|
|
|
78
|
+
async def _get_masking_report(params: dict, ctx: Any = None) -> dict:
|
|
79
|
+
from ..mix_engine.tools import get_masking_report
|
|
80
|
+
return await _call(get_masking_report, ctx, params)
|
|
81
|
+
|
|
82
|
+
|
|
68
83
|
async def _get_master_spectrum(params: dict, ctx: Any = None) -> dict:
|
|
69
84
|
from ..tools.analyzer import get_master_spectrum
|
|
70
85
|
return await _call(get_master_spectrum, ctx, params)
|
|
@@ -151,7 +166,10 @@ def build_mcp_dispatch_registry() -> dict[str, Callable]:
|
|
|
151
166
|
"load_sample_to_simpler": _load_sample_to_simpler,
|
|
152
167
|
"apply_automation_shape": _apply_automation_shape,
|
|
153
168
|
"apply_gesture_template": _apply_gesture_template,
|
|
169
|
+
"analyze_sample": _analyze_sample,
|
|
170
|
+
"analyze_synth_patch": _analyze_synth_patch,
|
|
154
171
|
"analyze_mix": _analyze_mix,
|
|
172
|
+
"get_masking_report": _get_masking_report,
|
|
155
173
|
"get_master_spectrum": _get_master_spectrum,
|
|
156
174
|
"get_emotional_arc": _get_emotional_arc,
|
|
157
175
|
"get_motif_graph": _get_motif_graph,
|
|
@@ -83,6 +83,8 @@ REMOTE_COMMANDS: frozenset[str] = frozenset({
|
|
|
83
83
|
"capture_midi", "start_recording", "stop_recording",
|
|
84
84
|
"get_cue_points", "jump_to_cue", "toggle_cue_point",
|
|
85
85
|
"back_to_arranger", "force_arrangement",
|
|
86
|
+
"arrangement_automation_via_session_record_start",
|
|
87
|
+
"arrangement_automation_via_session_record_complete",
|
|
86
88
|
# scales — Song + per-clip scale awareness (Live 12.0+)
|
|
87
89
|
"get_song_scale", "set_song_scale", "set_song_scale_mode",
|
|
88
90
|
"list_available_scales",
|
package/mcp_server/server.py
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
378
|
-
# rename based on naming conventions in other providers).
|
|
379
|
-
#
|
|
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.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"mcpName": "io.github.dreamrec/livepilot",
|
|
5
|
-
"description": "Agentic production system for Ableton Live 12
|
|
5
|
+
"description": "Agentic production system for Ableton Live 12 — 465 tools, 56 domains, 44 semantic moves. Device atlas (5264 devices, 120 enriched, 7 indexes), Splice intelligence (gRPC + GraphQL describe-a-sound + preview + collections + presets), 9-band spectral perception auto-loaded via ensure_analyzer_on_master, Creative Director skill, technique memory, 12 creative intelligence engines",
|
|
6
6
|
"author": "Pilot Studio",
|
|
7
7
|
"license": "BSL-1.1",
|
|
8
8
|
"type": "commonjs",
|
|
9
9
|
"bin": {
|
|
10
|
-
"livepilot": "
|
|
10
|
+
"livepilot": "bin/livepilot.js"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/dreamrec/LivePilot"
|
|
14
|
+
"url": "git+https://github.com/dreamrec/LivePilot.git"
|
|
15
15
|
},
|
|
16
16
|
"homepage": "https://github.com/dreamrec/LivePilot",
|
|
17
17
|
"bugs": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"files": [
|
|
48
48
|
"bin/**/*.js",
|
|
49
49
|
"installer/**/*.js",
|
|
50
|
+
"livepilot/**",
|
|
50
51
|
"mcp_server/**/*.py",
|
|
51
52
|
"mcp_server/**/*.json",
|
|
52
53
|
"mcp_server/**/*.yaml",
|
|
@@ -56,6 +57,9 @@
|
|
|
56
57
|
"m4l_device/LivePilot_Analyzer.amxd",
|
|
57
58
|
"m4l_device/LivePilot_Analyzer.adv",
|
|
58
59
|
"m4l_device/livepilot_bridge.js",
|
|
60
|
+
"m4l_device/LivePilot_Elektron.amxd",
|
|
61
|
+
"m4l_device/LivePilot_Elektron.maxpat",
|
|
62
|
+
"m4l_device/livepilot_elektron_bridge.js",
|
|
59
63
|
"m4l_device/BUILD_GUIDE.md",
|
|
60
64
|
"requirements.txt",
|
|
61
65
|
"README.md",
|
|
@@ -64,6 +68,17 @@
|
|
|
64
68
|
"server.json",
|
|
65
69
|
"!**/__pycache__/**",
|
|
66
70
|
"!**/*.pyc",
|
|
67
|
-
"!**/.DS_Store"
|
|
71
|
+
"!**/.DS_Store",
|
|
72
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/synths-m4l.md",
|
|
73
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/plugins-synths.md",
|
|
74
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/utility-and-workflow.md",
|
|
75
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/samples-and-irs.md",
|
|
76
|
+
"!livepilot/skills/livepilot-core/references/device-atlas/presets-by-vibe.md",
|
|
77
|
+
"!livepilot/skills/livepilot-devices/references/m4l-vendor/**",
|
|
78
|
+
"!livepilot/skills/livepilot-devices/references/m4l-depth-pass-findings.md",
|
|
79
|
+
"!livepilot/skills/livepilot-devices/references/m4l-depth-pass-resume.md",
|
|
80
|
+
"!livepilot/skills/livepilot-devices/references/m4l-library-deep.md",
|
|
81
|
+
"!livepilot/skills/livepilot-devices/references/m4l-master-reference.md",
|
|
82
|
+
"!livepilot/skills/livepilot-devices/references/m4l-technique-map.md"
|
|
68
83
|
]
|
|
69
84
|
}
|
|
@@ -5,7 +5,7 @@ Entry point for the ControlSurface. Ableton calls create_instance(c_instance)
|
|
|
5
5
|
when this script is selected in Preferences > Link, Tempo & MIDI.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "1.
|
|
8
|
+
__version__ = "1.26.1"
|
|
9
9
|
|
|
10
10
|
from _Framework.ControlSurface import ControlSurface
|
|
11
11
|
from . import router
|