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 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
- > Everything is reversible with undo.
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. **43 semantic moves** (v1.20) — musical intents like "tighten the low end" or "make kick and bass lock" that compile into tool sequences with risk levels and target dimensions |
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 32 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.
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
- **43 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.
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.0";
37
+ var VERSION = "1.21.1";
38
38
 
39
39
  // ── State ──────────────────────────────────────────────────────────────────
40
40
 
@@ -1,2 +1,2 @@
1
1
  """LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
2
- __version__ = "1.21.0"
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
- # Refuse to commit branches the classifier rejected or that were
699
- # analytical-only. Those statuses exist specifically so callers
700
- # can't route them into re-application, and ranked_branches()
701
- # already excludes them so reaching commit with such a branch
702
- # means the caller is bypassing the ranking layer.
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 in ("rejected", "analytical", "failed"):
722
+ if target.status != "evaluated":
707
723
  return {
708
724
  "error": (
709
- f"Cannot commit branch with status '{target.status}'. "
710
- f"'rejected' = hard-rule classifier rolled back; "
711
- f"'analytical' = no executable plan; "
712
- f"'failed' = zero steps applied successfully. "
713
- f"Use compare_experiments to see eligible winners "
714
- f"(only status='evaluated' branches are ranking candidates)."
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.0",
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, 43 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",
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.0"
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, 43 semantic moves, device atlas (1305 devices), Splice intelligence (gRPC + GraphQL), 9-band spectral perception auto-loaded, Creative Director skill, technique memory, 12 creative engines",
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.0",
9
+ "version": "1.21.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "livepilot",
14
- "version": "1.21.0",
14
+ "version": "1.21.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  }