livepilot 1.21.0 → 1.21.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 +118 -0
- package/README.md +6 -4
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +1 -1
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/experiment/tools.py +36 -12
- package/package.json +2 -2
- package/remote_script/LivePilot/__init__.py +1 -1
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,123 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.21.1 — Audit-response patch: experiment-commit safety + doc hygiene + lockfile (April 24 2026)
|
|
4
|
+
|
|
5
|
+
Small patch release responding to an external audit of v1.21.0 performed
|
|
6
|
+
the same day it shipped. The audit surfaced one real safety bug
|
|
7
|
+
(commit_experiment status allowlist was an exclusion list when the
|
|
8
|
+
intent was an inclusion list) plus several doc-consistency drifts.
|
|
9
|
+
No new features. No API changes beyond the tightened commit_experiment
|
|
10
|
+
contract. v1.21.0 callers already doing the right thing
|
|
11
|
+
(run_experiment → commit the ranked winner) continue to work unchanged.
|
|
12
|
+
|
|
13
|
+
### P1 — commit_experiment only accepts `status='evaluated'`
|
|
14
|
+
|
|
15
|
+
Pre-fix (v1.21.0 and all prior versions with commit_experiment), the
|
|
16
|
+
status check was an EXCLUSION list:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
if target.status in ("rejected", "analytical", "failed"):
|
|
20
|
+
return {"error": ...}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Blocks 3 statuses; implicitly allows the other 6 — including `pending`,
|
|
24
|
+
`running`, `discarded`, and `interesting_but_failed`. Those branches
|
|
25
|
+
can't be ranked by `compare_experiments()`, but `commit_experiment`
|
|
26
|
+
would accept them as long as a compiled plan was attached. The code's
|
|
27
|
+
own inline comment already described the correct contract ("only
|
|
28
|
+
status='evaluated' branches are ranking candidates"); the implementation
|
|
29
|
+
had the wrong polarity. The fix flips it to an INCLUSION check:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
if target.status != "evaluated":
|
|
33
|
+
return {"error": ...}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Error message updated to enumerate all 9 possible statuses and explain
|
|
37
|
+
which state each represents (pending/running = not yet evaluated;
|
|
38
|
+
rejected/analytical/failed = classifier exclusions; committed =
|
|
39
|
+
already committed; discarded = explicitly thrown out;
|
|
40
|
+
interesting_but_failed = exploration-audit only).
|
|
41
|
+
|
|
42
|
+
Why this matters: v1.21.0's `commit_experiment` ledger writer records
|
|
43
|
+
every commit into `SessionLedger` where anti-repetition filters read
|
|
44
|
+
it. Without the tighter status check, a caller bypassing the ranking
|
|
45
|
+
layer could pollute the ledger with entries the system explicitly
|
|
46
|
+
classified as non-winners — degrading anti-repetition signal quality.
|
|
47
|
+
|
|
48
|
+
**Regression tests added (4)** in `tests/test_commit_experiment_ledger.py`:
|
|
49
|
+
`test_commit_on_pending_branch_rejects`,
|
|
50
|
+
`test_commit_on_running_branch_rejects`,
|
|
51
|
+
`test_commit_on_discarded_branch_rejects`,
|
|
52
|
+
`test_commit_on_interesting_but_failed_branch_rejects`. All FAILED
|
|
53
|
+
pre-fix (reproducing the audit's finding), all PASS post-fix.
|
|
54
|
+
|
|
55
|
+
### P1 — package-lock.json bumped 1.17.5 → 1.21.1
|
|
56
|
+
|
|
57
|
+
Lockfile's root `.version` and `.packages[""].version` had been stale
|
|
58
|
+
at 1.17.5 since before v1.18. `npm publish` doesn't read these fields
|
|
59
|
+
(it reads package.json), so the npm registry was always correct — but
|
|
60
|
+
the repo-local lockfile misled local `npm install` workflows and any
|
|
61
|
+
release-check tooling that compared package.json vs lockfile. Fixed by
|
|
62
|
+
surgical replace on the 2 stale strings; no dependency tree
|
|
63
|
+
regeneration (keeps dep versions identical to v1.21.0).
|
|
64
|
+
|
|
65
|
+
### P2 — Analyzer tool count: 32/33 → 38 (actual)
|
|
66
|
+
|
|
67
|
+
README.md previously said "32 spectral/analyzer tools" in one place
|
|
68
|
+
and "38 analyzer tools" in another — inconsistent within the same file.
|
|
69
|
+
`docs/M4L_BRIDGE.md` said "33 MCP tools in the analyzer domain" in two
|
|
70
|
+
places. Actual `@mcp.tool` count in `mcp_server/tools/analyzer.py` is
|
|
71
|
+
**38** (grep-verified). All stale 32/33 refs corrected to 38.
|
|
72
|
+
|
|
73
|
+
### P2 — Reversibility language hedge
|
|
74
|
+
|
|
75
|
+
README's header NOTE block said "Everything is reversible with undo,"
|
|
76
|
+
which is too strong. Live-session mutations (clips, devices, mixer,
|
|
77
|
+
arrangement) do route through Ableton's undo stack and are reversible
|
|
78
|
+
— but Splice downloads, memory/ledger writes, installer actions, atlas
|
|
79
|
+
scans, and filesystem writes persist beyond undo. Hedged the language
|
|
80
|
+
to reflect this.
|
|
81
|
+
|
|
82
|
+
### Deferred to v1.22
|
|
83
|
+
|
|
84
|
+
Audit-surfaced items that aren't patch-release material:
|
|
85
|
+
|
|
86
|
+
- **Atlas statistics reconciliation.** Docs claim "1305 devices / 120
|
|
87
|
+
enriched / 641 pack-indexed" across 9 description fields, but the
|
|
88
|
+
shipped `device_atlas.json` has 5264 devices and 135 entries with
|
|
89
|
+
`.enriched` truthy. The "1305" number appears to be a long-stale
|
|
90
|
+
cargo-culted count. Requires deciding whether `.devices` contains
|
|
91
|
+
duplicates, what the canonical "enriched" definition is, and
|
|
92
|
+
whether to restructure atlas JSON or fix the readers that look for
|
|
93
|
+
`.meta.version`. v1.22 scope.
|
|
94
|
+
- **`sync_metadata` expansion** to check package-lock.json project
|
|
95
|
+
version, semantic-move count via `registry.count()`, and
|
|
96
|
+
analyzer-tool count via grep on `analyzer.py`. Would convert this
|
|
97
|
+
entire class of drift into CI failures.
|
|
98
|
+
- **Dev-install path** for local contributors hitting missing
|
|
99
|
+
`soundfile` / `scipy` / `pretty_midi` / `pytest_asyncio` deps during
|
|
100
|
+
bare-python local runs. CI has these installed via requirements.txt.
|
|
101
|
+
|
|
102
|
+
### Credits
|
|
103
|
+
|
|
104
|
+
External audit performed same day v1.21.0 shipped. Findings
|
|
105
|
+
file-linked and reproducible. Response time: ~2 hours from audit
|
|
106
|
+
receipt to v1.21.1 patch shipping.
|
|
107
|
+
|
|
108
|
+
### Scope stats
|
|
109
|
+
|
|
110
|
+
- 1 code fix (`mcp_server/experiment/tools.py` — commit_experiment status check)
|
|
111
|
+
- 4 new regression tests (all initially FAILING pre-fix to reproduce
|
|
112
|
+
the audit, all PASSING post-fix)
|
|
113
|
+
- 3 doc corrections (README.md × 2, docs/M4L_BRIDGE.md × 2, plus the
|
|
114
|
+
reversibility hedge)
|
|
115
|
+
- 15 version-string sites + `.amxd` binary patch (2 bytes) +
|
|
116
|
+
package-lock.json (2 version fields)
|
|
117
|
+
- Test suite: 3120 → 3124 pass (+4). Zero regressions.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
3
121
|
## 1.21.0 — Consolidation: experiment ledger + preset library + record-readiness + reader audit (April 24 2026)
|
|
4
122
|
|
|
5
123
|
Consolidation release closing five items from the v1.20 plan §12 non-goals
|
package/README.md
CHANGED
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
> [!NOTE]
|
|
26
26
|
> LivePilot works with **any MCP client** — Claude Code, Claude Desktop, Cursor, VS Code, Windsurf.
|
|
27
27
|
> All tools execute on Ableton's main thread through the official Live Object Model API.
|
|
28
|
-
>
|
|
28
|
+
> Live-session mutations (clips, devices, mixer, arrangement) route through Ableton's undo stack.
|
|
29
|
+
> Side effects that touch state outside the Live project — Splice downloads, memory/ledger writes,
|
|
30
|
+
> installer actions, atlas scans, filesystem writes — persist beyond undo.
|
|
29
31
|
|
|
30
32
|
<br>
|
|
31
33
|
|
|
@@ -43,7 +45,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
43
45
|
| **Sample Engine** | Three-source sample intelligence — Ableton's browser, your filesystem, and Splice's catalog (plan-aware: Ableton Live plan uses daily quota, Sounds+/Creator uses credits, free samples bypass both). 6 fitness critics. 29 processing techniques. Collections, presets, preview-URL audition, LIVE Describe-a-Sound + Variations via Splice GraphQL |
|
|
44
46
|
| **Spectral Perception** | Real-time ears via M4L — 9-band FFT (with sub_low split at 20-60 Hz for kick fundamentals), RMS/peak metering, Krumhansl-Schmuckler key detection, pitch tracking, FluCoMa mel/chroma/onset. Auto-loaded via `ensure_analyzer_on_master` (v1.20.3) — no more silently-degraded mix moves from forgotten analyzer |
|
|
45
47
|
| **Technique Memory** | Persistent library of production decisions. Save a beat pattern, device chain, or mix template. Recall by mood, genre, or texture across sessions |
|
|
46
|
-
| **Creative Intelligence** | 12 engines on top of the tools: SongBrain, Taste Graph, Wonder Mode, Mix/Sound-Design/Transition/Reference/Translation engines, Hook Hunter, Stuckness Detector, Session Continuity, Preview Studio. **
|
|
48
|
+
| **Creative Intelligence** | 12 engines on top of the tools: SongBrain, Taste Graph, Wonder Mode, Mix/Sound-Design/Transition/Reference/Translation engines, Hook Hunter, Stuckness Detector, Session Continuity, Preview Studio. **44 semantic moves** (v1.21) — musical intents like "tighten the low end" or "make kick and bass lock" that compile into tool sequences with risk levels and target dimensions |
|
|
47
49
|
|
|
48
50
|
<br>
|
|
49
51
|
|
|
@@ -101,7 +103,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
|
|
|
101
103
|
|
|
102
104
|
**MCP Server** (`mcp_server/`) — Python FastMCP server. Validates inputs, routes commands to the Remote Script over TCP, manages the M4L bridge, runs the atlas, sample engine, composer, and all intelligence engines. This is what your AI client connects to.
|
|
103
105
|
|
|
104
|
-
**M4L Bridge** (`m4l_device/`) — Optional Max for Live Audio Effect on the master track. Provides deep LOM access through Max's LiveAPI that the ControlSurface API can't reach. UDP 9880 (M4L to server) carries spectral data and LiveAPI responses. OSC 9881 (server to M4L) sends commands. The
|
|
106
|
+
**M4L Bridge** (`m4l_device/`) — Optional Max for Live Audio Effect on the master track. Provides deep LOM access through Max's LiveAPI that the ControlSurface API can't reach. UDP 9880 (M4L to server) carries spectral data and LiveAPI responses. OSC 9881 (server to M4L) sends commands. The 38 spectral/analyzer tools strictly require the bridge; device and sample tools that call the bridge also have graceful fallbacks, so core functionality works without it. Backed by 31 bridge commands for hidden parameters, Simpler internals, warp markers, display values, and Simpler warp / Compressor sidechain writes that live on child objects Python can't reach.
|
|
105
107
|
|
|
106
108
|
**Device Atlas** (`mcp_server/atlas/`) — In-memory indexed JSON database. 1305 devices with browser URIs, 120 enriched with YAML sonic intelligence profiles (mood, genre, texture, recommended chains). 7 indexes: by_id, by_name, by_uri, by_category, by_tag, by_genre, by_pack (641 devices mapped to their source pack). Reverse-index `device_techniques_index.json` powers `atlas_techniques_for_device` (146 cross-references across 58 devices). The AI never hallucinates a device name or preset — it always resolves against the atlas first.
|
|
107
109
|
|
|
@@ -133,7 +135,7 @@ Learns your production preferences across sessions. Tracks which move families y
|
|
|
133
135
|
|
|
134
136
|
### Semantic Moves — Musical Actions, Not Parameters
|
|
135
137
|
|
|
136
|
-
**
|
|
138
|
+
**44 high-level intents** across 7 families (mix, arrangement, transition, sound_design, performance, device_creation, sample) — "add contrast," "tighten the low end," "make kick and bass lock," "sample vocal ghost," "destroy then rebuild." Each move compiles into a concrete tool sequence with risk level, target dimensions, and protection thresholds. Analyzer-gated moves (`tighten_low_end`, `make_kick_bass_lock`) mark their spectrum pre-reads as optional so the plan continues even when the analyzer isn't available. The AI knows what it's risking with every action.
|
|
137
139
|
|
|
138
140
|
### Wonder Mode — Stuck-Rescue Workflow
|
|
139
141
|
|
|
Binary file
|
|
@@ -34,7 +34,7 @@ outlets = 2; // 0: to udpsend (responses), 1: to buffer~/status
|
|
|
34
34
|
// Single source of truth for the bridge version — bumped alongside the
|
|
35
35
|
// rest of the release manifest. Surfaced in the UI via messnamed("livepilot_version", ...)
|
|
36
36
|
// so the frozen .amxd visibly reports which build it was last exported from.
|
|
37
|
-
var VERSION = "1.21.
|
|
37
|
+
var VERSION = "1.21.1";
|
|
38
38
|
|
|
39
39
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
40
40
|
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.21.
|
|
2
|
+
__version__ = "1.21.1"
|
|
@@ -695,23 +695,47 @@ async def commit_experiment(
|
|
|
695
695
|
if not experiment:
|
|
696
696
|
return {"error": f"Experiment {experiment_id} not found"}
|
|
697
697
|
|
|
698
|
-
#
|
|
699
|
-
#
|
|
700
|
-
#
|
|
701
|
-
#
|
|
702
|
-
#
|
|
698
|
+
# v1.21.1 fix (external audit 2026-04-24): accept ONLY status='evaluated'.
|
|
699
|
+
# Pre-fix, the check was an exclusion list —
|
|
700
|
+
# `if target.status in ("rejected", "analytical", "failed"):` — which
|
|
701
|
+
# implicitly allowed 'pending', 'running', 'discarded', and
|
|
702
|
+
# 'interesting_but_failed' to commit even though
|
|
703
|
+
# compare_experiments() never ranks them. The code's inline comment
|
|
704
|
+
# below ("only status='evaluated' branches are ranking candidates")
|
|
705
|
+
# already described the correct contract; this fix flips the
|
|
706
|
+
# polarity so the implementation matches. See
|
|
707
|
+
# docs/plans/v1.21-impl-status.md Appendix C for the audit-response log.
|
|
708
|
+
#
|
|
709
|
+
# Status semantics (from ExperimentBranch lifecycle):
|
|
710
|
+
# pending — create_experiment landed; run_experiment hasn't touched it
|
|
711
|
+
# running — run_experiment is mid-flight on this branch
|
|
712
|
+
# evaluated — run_experiment finished; ranking candidate ✓
|
|
713
|
+
# rejected — hard-rule classifier rolled back (protect violation, etc.)
|
|
714
|
+
# analytical — no executable plan (seed was analytical_only)
|
|
715
|
+
# failed — zero steps applied successfully
|
|
716
|
+
# committed — already committed (re-commit is wrong)
|
|
717
|
+
# discarded — caller explicitly threw it out
|
|
718
|
+
# interesting_but_failed — exploration-mode audit trail; not ranked
|
|
703
719
|
target = experiment.get_branch(branch_id)
|
|
704
720
|
if target is None:
|
|
705
721
|
return {"error": f"Branch {branch_id} not found"}
|
|
706
|
-
if target.status
|
|
722
|
+
if target.status != "evaluated":
|
|
707
723
|
return {
|
|
708
724
|
"error": (
|
|
709
|
-
f"Cannot commit branch with status '{target.status}'
|
|
710
|
-
f"'
|
|
711
|
-
f"
|
|
712
|
-
f"'
|
|
713
|
-
f"
|
|
714
|
-
f"
|
|
725
|
+
f"Cannot commit branch with status '{target.status}' — "
|
|
726
|
+
f"only status='evaluated' branches are commit candidates. "
|
|
727
|
+
f"Reason depends on current status: "
|
|
728
|
+
f"'pending' / 'running' = run_experiment hasn't evaluated "
|
|
729
|
+
f"this branch yet (run it first); "
|
|
730
|
+
f"'rejected' = hard-rule classifier rolled it back; "
|
|
731
|
+
f"'analytical' = no executable plan (analytical_only seed); "
|
|
732
|
+
f"'failed' = zero steps applied successfully during run; "
|
|
733
|
+
f"'committed' = already committed (don't re-run); "
|
|
734
|
+
f"'discarded' = caller explicitly threw this branch out; "
|
|
735
|
+
f"'interesting_but_failed' = kept for audit in "
|
|
736
|
+
f"exploration mode, but classifier excluded from ranking. "
|
|
737
|
+
f"Use compare_experiments to see eligible (ranked) "
|
|
738
|
+
f"winners — they are always status='evaluated'."
|
|
715
739
|
),
|
|
716
740
|
"branch_id": branch_id,
|
|
717
741
|
"branch_status": target.status,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livepilot",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"mcpName": "io.github.dreamrec/livepilot",
|
|
5
|
-
"description": "Agentic production system for Ableton Live 12 — 430 tools, 53 domains,
|
|
5
|
+
"description": "Agentic production system for Ableton Live 12 — 430 tools, 53 domains, 44 semantic moves. Device atlas (1305 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",
|
|
@@ -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.21.
|
|
8
|
+
__version__ = "1.21.1"
|
|
9
9
|
|
|
10
10
|
from _Framework.ControlSurface import ControlSurface
|
|
11
11
|
from . import router
|
package/server.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.dreamrec/livepilot",
|
|
4
|
-
"description": "430-tool agentic MCP production system for Ableton Live 12 — 53 domains,
|
|
4
|
+
"description": "430-tool agentic MCP production system for Ableton Live 12 — 53 domains, 44 semantic moves, device atlas (1305 devices), Splice intelligence (gRPC + GraphQL), 9-band spectral perception auto-loaded, Creative Director skill, technique memory, 12 creative engines",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/dreamrec/LivePilot",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.21.
|
|
9
|
+
"version": "1.21.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "livepilot",
|
|
14
|
-
"version": "1.21.
|
|
14
|
+
"version": "1.21.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|