livepilot 1.18.2 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.18.3 — Brief compliance runtime check (#7 + #8) (April 24 2026)
4
+
5
+ Third v1.18.x patch. Bundles two Known Issues items (#7 + #8) that
6
+ shared the same "check tool args against brief constraints" machinery.
7
+
8
+ ### Fix
9
+
10
+ - **#7 Packet `avoid` list runtime enforcement.**
11
+ - **#8 `locked_dimensions` runtime enforcement.**
12
+
13
+ Both were advisory-only pre-v1.18.3: the director SKILL.md documented
14
+ the hard-filter rules but no runtime machinery verified compliance.
15
+ This release ships a **stateless pure check function** in a new
16
+ `mcp_server/creative_director` module, exposed as the MCP tool
17
+ `check_brief_compliance(brief, tool_name, tool_args)`.
18
+
19
+ **Usage**: director's Phase 6 calls the tool before each risky
20
+ execution (EQ parameters, filter settings, new scene creation, clip
21
+ note editing, send routing, etc.). The tool returns
22
+ `{"ok": bool, "violations": [...]}`. Violations are reports, not
23
+ automatic blocks — the director surfaces them to the user and offers
24
+ three paths: adjust, override-for-this-turn, or pick a different tool.
25
+
26
+ **Detection strategy — best-effort heuristic**, not semantic
27
+ understanding:
28
+
29
+ - anti_pattern matching via keyword tokens + parameter-name heuristics
30
+ (e.g., pattern "bright top-end" + Hi Gain positive value → fires)
31
+ - locked_dimension matching via tool → dimension map
32
+ (e.g., structural lock + create_scene → fires)
33
+
34
+ ### Infrastructure
35
+
36
+ - NEW module `mcp_server/creative_director/` with compliance.py +
37
+ tools.py
38
+ - NEW MCP tool `check_brief_compliance` (tool count 427 → 428,
39
+ domain count 52 → 53)
40
+ - Director SKILL.md Phase 6 now documents the check + the
41
+ three-path violation-response protocol
42
+ - Full session-state active-brief storage is deferred to v1.19;
43
+ v1.18.3 is stateless (caller passes brief each time)
44
+
45
+ ### Tests added
46
+
47
+ - `test_compliance_check_detects_anti_pattern_violation` (BC packet
48
+ + Hi Gain boost → violation)
49
+ - `test_compliance_check_detects_locked_dimension_violation`
50
+ (structural lock + create_scene → violation)
51
+ - `test_compliance_check_passes_compliant_call` (no false positives)
52
+ - `test_compliance_check_empty_brief_permissive` (fresh session
53
+ safety)
54
+
55
+ Test suite: 2792 pass, 1 skipped. Zero regressions.
56
+
57
+ ### Still open for v1.19 (3 items)
58
+
59
+ - Experiment state continuity between branches (architectural —
60
+ transport-state locking needed)
61
+ - Hybrid-packet compilation algorithm (union/intersection logic for
62
+ multi-packet refs like "Basic Channel meets Dilla")
63
+ - Full architectural fix for #3 (route director Phase 6 through
64
+ `apply_semantic_move` / `commit_experiment` — replaces the
65
+ doc-level fix shipped in v1.18.1)
66
+
67
+ These are v1.19 scope — each needs new architectural decisions and
68
+ infrastructure unsuitable for patch releases.
69
+
3
70
  ## 1.18.2 — Wonder cold-start + tie-break + genre catalog closure (April 24 2026)
4
71
 
5
72
  Second patch in the v1.18.x series. Three items from the v1.18.0/v1.18.1
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  <p align="center">
19
19
  An agentic production system for Ableton Live 12.<br>
20
- 427 tools. 52 domains. Device atlas. Plan-aware Splice integration. Auto-composition. Spectral perception. Technique memory. Drum-rack pad builder. Live dead-device detection.
20
+ 428 tools. 53 domains. Device atlas. Plan-aware Splice integration. Auto-composition. Spectral perception. Technique memory. Drum-rack pad builder. Live dead-device detection.
21
21
  </p>
22
22
 
23
23
  <br>
@@ -80,8 +80,8 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
80
80
  │ └─────────────────┼──────────────────┘ │
81
81
  │ ▼ │
82
82
  │ ┌─────────────────┐ │
83
- │ │ 427 MCP Tools │ │
84
- │ │ 52 domains │ │
83
+ │ │ 428 MCP Tools │ │
84
+ │ │ 53 domains │ │
85
85
  │ └────────┬────────┘ │
86
86
  │ │ │
87
87
  │ Remote Script ──┤── TCP 9878 │
@@ -121,7 +121,7 @@ Most MCP servers are tool collections — they execute commands. LivePilot is an
121
121
 
122
122
  ## The Intelligence Layer
123
123
 
124
- 12 engines sit on top of the 427 tools. They give the AI musical judgment, not just musical execution.
124
+ 12 engines sit on top of the 428 tools. They give the AI musical judgment, not just musical execution.
125
125
 
126
126
  ### SongBrain — What the Song Is
127
127
 
@@ -173,7 +173,7 @@ Every engine follows: **measure before → act → measure after → compare**.
173
173
 
174
174
  ## Tools
175
175
 
176
- 427 tools across 52 domains. Highlights below — [full catalog here](docs/manual/tool-catalog.md).
176
+ 428 tools across 53 domains. Highlights below — [full catalog here](docs/manual/tool-catalog.md).
177
177
 
178
178
  <br>
179
179
 
@@ -362,7 +362,7 @@ The V2 intelligence layer. These tools analyze, diagnose, plan, evaluate, and le
362
362
  | Creative Constraints | 5 | constraint activation, reference-inspired variants |
363
363
  | Preview Studio | 5 | variant creation, preview rendering, comparison, commit |
364
364
 
365
- > **[View all 427 tools →](docs/manual/tool-catalog.md)**
365
+ > **[View all 428 tools →](docs/manual/tool-catalog.md)**
366
366
 
367
367
  <br>
368
368
 
@@ -589,7 +589,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for architecture details, code guidelines
589
589
 
590
590
  | Document | What's inside |
591
591
  |----------|---------------|
592
- | [Manual](docs/manual/index.md) | Complete reference: architecture, all 427 tools, workflows |
592
+ | [Manual](docs/manual/index.md) | Complete reference: architecture, all 428 tools, workflows |
593
593
  | [Intelligence Layer](docs/manual/intelligence.md) | How the 12 engines connect — conductor, moves, preview, evaluation |
594
594
  | [Device Atlas](docs/manual/device-atlas.md) | 1305 devices indexed — search, suggest, chain building |
595
595
  | [Samples & Slicing](docs/manual/samples.md) | 3-source search, fitness critics, slice workflows |
@@ -1,2 +1,2 @@
1
1
  """LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
2
- __version__ = "1.18.2"
2
+ __version__ = "1.18.3"
@@ -0,0 +1,21 @@
1
+ """Creative Director — v1.18.3+ runtime compliance check for brief constraints.
2
+
3
+ The livepilot-creative-director skill compiles a Creative Brief inline in
4
+ each creative turn. The brief's `anti_patterns` and `locked_dimensions`
5
+ fields were previously advisory — no runtime machinery verified that
6
+ intended tool calls respected them.
7
+
8
+ This module ships the minimum-effective enforcement layer: a pure
9
+ check function `check_brief_compliance(brief, tool_name, tool_args)`
10
+ that returns {"ok": bool, "violations": [...]}. Director's Phase 6
11
+ calls it before each risky tool execution. Violations don't block
12
+ execution automatically — the director reports them to the user, who
13
+ can override or abandon.
14
+
15
+ Full session-state active-brief storage + automatic interception is a
16
+ v1.19 scope item.
17
+ """
18
+
19
+ from .compliance import check_brief_compliance
20
+
21
+ __all__ = ["check_brief_compliance"]
@@ -0,0 +1,263 @@
1
+ """Brief compliance check — v1.18.3 pure function for anti-pattern and
2
+ locked-dimension enforcement.
3
+
4
+ Pure computation: no I/O, no session state. Caller passes the brief
5
+ dict and the intended tool call; the function returns a report of
6
+ violations. Director's Phase 6 calls this before each risky tool call.
7
+
8
+ Design principles:
9
+
10
+ 1. **Best-effort heuristic, not semantic understanding.** anti_patterns
11
+ in the brief are prose. The checker does keyword-token matching
12
+ against humanized tool-call descriptions. Won't catch every
13
+ violation (e.g., "too muddy" → EQ cut at 300 Hz requires more
14
+ intelligence than substring match). Does catch obvious ones
15
+ (e.g., "bright top-end" → Hi Gain boost).
16
+
17
+ 2. **Never block — always report.** The return format is a violations
18
+ list with human-readable reason + suggestion. The caller (director)
19
+ decides whether to proceed, ask the user, or abandon. Hard-blocking
20
+ at this layer would crash under false positives.
21
+
22
+ 3. **Empty brief passes everything.** A brief without anti_patterns or
23
+ locked_dimensions returns ok=True for all calls — we don't want a
24
+ fresh session to be hostile to experimentation.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import re
30
+ from typing import Any
31
+
32
+
33
+ # ── Tool → dimension mapping ────────────────────────────────────────
34
+ # Maps MCP tool names to the creative dimension they primarily affect.
35
+ # Used for locked_dimensions enforcement. A tool can map to None
36
+ # (dimension-agnostic — e.g., undo, get_session_info) in which case no
37
+ # locked-dimension check applies.
38
+
39
+ _STRUCTURAL_TOOLS = frozenset({
40
+ "create_scene", "delete_scene", "duplicate_scene", "set_scene_name",
41
+ "set_scene_tempo", "set_scene_color", "fire_scene",
42
+ "set_clip_follow_action", "set_scene_follow_action",
43
+ "capture_and_insert_scene",
44
+ "create_arrangement_clip", "create_native_arrangement_clip",
45
+ "force_arrangement", "plan_arrangement",
46
+ "transform_section", "refresh_repeated_section",
47
+ })
48
+
49
+ _RHYTHMIC_TOOLS = frozenset({
50
+ "add_notes", "modify_notes", "remove_notes", "transpose_notes",
51
+ "duplicate_notes", "add_arrangement_notes", "modify_arrangement_notes",
52
+ "remove_arrangement_notes", "quantize_clip",
53
+ "assign_clip_groove", "set_groove_params", "set_song_groove_amount",
54
+ "apply_gesture_template",
55
+ "generate_euclidean_rhythm", "layer_euclidean_rhythms",
56
+ "generate_countermelody", "transform_motif",
57
+ })
58
+
59
+ _TIMBRAL_TOOLS = frozenset({
60
+ "set_device_parameter", "batch_set_parameters",
61
+ "load_browser_item", "find_and_load_device",
62
+ "load_device_by_uri", "insert_device", "delete_device", "move_device",
63
+ "toggle_device", "copy_device_state",
64
+ "install_m4l_device",
65
+ })
66
+
67
+ _SPATIAL_TOOLS = frozenset({
68
+ "set_track_send", "set_track_pan", "set_track_volume",
69
+ "set_master_volume",
70
+ "create_return_track",
71
+ "set_track_routing",
72
+ })
73
+
74
+
75
+ def _tool_to_dimension(tool_name: str, tool_args: dict) -> str | None:
76
+ """Map an MCP tool call to its primary creative dimension.
77
+
78
+ Returns one of {"structural", "rhythmic", "timbral", "spatial"} or
79
+ None if the tool is dimension-agnostic.
80
+
81
+ Some tools (e.g., load_browser_item) are timbral EXCEPT when loading
82
+ a device on a return track, which is spatial. The heuristic resolves
83
+ this via track_index: negative indices indicate return tracks.
84
+ """
85
+ if tool_name in _STRUCTURAL_TOOLS:
86
+ return "structural"
87
+ if tool_name in _RHYTHMIC_TOOLS:
88
+ return "rhythmic"
89
+ if tool_name in _SPATIAL_TOOLS:
90
+ return "spatial"
91
+ if tool_name in _TIMBRAL_TOOLS:
92
+ # load_browser_item on a return track is spatial, not timbral —
93
+ # loading Echo/Reverb/Auto Filter on a return is send-chain work.
94
+ track_index = tool_args.get("track_index")
95
+ if isinstance(track_index, int) and track_index < 0 and track_index != -1000:
96
+ return "spatial"
97
+ return "timbral"
98
+ return None
99
+
100
+
101
+ # ── Anti-pattern token matching ────────────────────────────────────
102
+
103
+ # Phrases that describe parameter changes indicative of "bright" moves
104
+ _BRIGHTENING_PARAM_KEYWORDS = ("hi gain", "hi freq", "high gain", "brightness",
105
+ "treble", "presence", "air")
106
+ # Phrases indicative of "aggressive transient" moves
107
+ _TRANSIENT_BOOST_KEYWORDS = ("transient", "attack", "punch", "snappy")
108
+ # Phrases indicative of "sidechain" moves
109
+ _SIDECHAIN_KEYWORDS = ("sidechain", "envelope follower", "ducking")
110
+ # Phrases indicative of "quantization" moves
111
+ _QUANTIZE_KEYWORDS = ("quantize", "snap", "full-grid", "perfectly quantized")
112
+
113
+
114
+ def _humanize_tool_call(tool_name: str, tool_args: dict) -> str:
115
+ """Produce a prose description of a tool call for keyword matching.
116
+
117
+ Best-effort — the output is not structured, just a lowercased string
118
+ that concatenates the tool name + notable arg values.
119
+ """
120
+ parts = [tool_name]
121
+ for key, val in (tool_args or {}).items():
122
+ if isinstance(val, (str, int, float, bool)):
123
+ parts.append(f"{key}={val}")
124
+ return " ".join(parts).lower()
125
+
126
+
127
+ def _anti_pattern_matches(pattern: str, tool_name: str, tool_args: dict) -> bool:
128
+ """Decide whether an anti_pattern phrase flags this tool call.
129
+
130
+ Strategy: lowercase the pattern, pull content keywords, match against
131
+ the humanized call + known parameter-name heuristics.
132
+ """
133
+ pattern_lower = pattern.lower()
134
+ call_desc = _humanize_tool_call(tool_name, tool_args)
135
+
136
+ # Direct substring match — cheapest first
137
+ # Split pattern into words, check if any significant word appears
138
+ # in the call description
139
+ stopwords = {"the", "a", "an", "and", "or", "of", "to", "in", "on", "at", "with", "for", "/", "-"}
140
+ pattern_tokens = [w.strip("—-./,:;") for w in re.split(r"\s+", pattern_lower)]
141
+ pattern_tokens = [w for w in pattern_tokens if w and w not in stopwords and len(w) >= 3]
142
+
143
+ # Check parameter-name heuristics for common anti-patterns
144
+ if any(kw in pattern_lower for kw in ("bright", "top-end", "top end", "highs")):
145
+ param_name = str(tool_args.get("parameter_name", "")).lower()
146
+ value = tool_args.get("value")
147
+ if any(bright_kw in param_name for bright_kw in _BRIGHTENING_PARAM_KEYWORDS):
148
+ # Boosting (positive value on a gain parameter) is the violation
149
+ if isinstance(value, (int, float)) and value > 0:
150
+ return True
151
+
152
+ if any(kw in pattern_lower for kw in ("transient", "aggressive transient",
153
+ "transient-heavy", "crisp")):
154
+ param_name = str(tool_args.get("parameter_name", "")).lower()
155
+ if any(t_kw in param_name for t_kw in _TRANSIENT_BOOST_KEYWORDS):
156
+ value = tool_args.get("value")
157
+ if isinstance(value, (int, float)) and value > 0.5:
158
+ return True
159
+
160
+ if any(kw in pattern_lower for kw in ("sidechain", "pumping")):
161
+ if tool_name == "compressor_set_sidechain":
162
+ return True
163
+ param_name = str(tool_args.get("parameter_name", "")).lower()
164
+ if any(sc_kw in param_name for sc_kw in _SIDECHAIN_KEYWORDS):
165
+ return True
166
+
167
+ if any(kw in pattern_lower for kw in ("full-grid", "full grid",
168
+ "quantized", "perfectly quantized")):
169
+ if tool_name == "quantize_clip":
170
+ # Quantize to tight grid (1/16 or finer, strong amount) is the violation
171
+ return True
172
+
173
+ # Fallback: token-level substring match
174
+ for token in pattern_tokens:
175
+ if token in call_desc:
176
+ return True
177
+
178
+ return False
179
+
180
+
181
+ # ── Public API ──────────────────────────────────────────────────────
182
+
183
+ def check_brief_compliance(
184
+ brief: dict,
185
+ tool_name: str,
186
+ tool_args: dict | None = None,
187
+ ) -> dict:
188
+ """Check whether a tool call complies with the active creative brief.
189
+
190
+ brief: compiled Creative Brief dict (may contain anti_patterns,
191
+ locked_dimensions, reference_anchors, etc.).
192
+ tool_name: the MCP tool about to be called.
193
+ tool_args: the dict of arguments.
194
+
195
+ Returns:
196
+ {
197
+ "ok": bool,
198
+ "violations": [
199
+ {
200
+ "rule": "anti_pattern" | "locked_dimension",
201
+ "detail": <pattern or dimension string>,
202
+ "reason": "...",
203
+ "suggestion": "...",
204
+ },
205
+ ...
206
+ ],
207
+ }
208
+
209
+ Empty brief (no anti_patterns, no locked_dimensions) always returns
210
+ ok=True with empty violations list. Best-effort heuristic — not
211
+ semantic understanding. Caller (director Phase 6) decides whether
212
+ to proceed, surface to user, or abandon.
213
+ """
214
+ tool_args = tool_args or {}
215
+ violations: list[dict[str, Any]] = []
216
+
217
+ # 1. Check anti_patterns
218
+ anti_patterns = brief.get("anti_patterns", []) or []
219
+ for pattern in anti_patterns:
220
+ if not isinstance(pattern, str) or not pattern.strip():
221
+ continue
222
+ if _anti_pattern_matches(pattern, tool_name, tool_args):
223
+ violations.append({
224
+ "rule": "anti_pattern",
225
+ "detail": pattern,
226
+ "reason": (
227
+ f"Tool call '{tool_name}' appears to violate the "
228
+ f"anti_pattern '{pattern}' from the active brief."
229
+ ),
230
+ "suggestion": (
231
+ "Either (a) adjust the call to avoid this pattern, "
232
+ "(b) ask the user to explicitly override this "
233
+ "specific anti_pattern, or (c) pick a different "
234
+ "tool that achieves the creative goal without "
235
+ "triggering the avoid rule."
236
+ ),
237
+ })
238
+
239
+ # 2. Check locked_dimensions
240
+ locked_dims = brief.get("locked_dimensions", []) or []
241
+ tool_dimension = _tool_to_dimension(tool_name, tool_args)
242
+ if tool_dimension and tool_dimension in locked_dims:
243
+ violations.append({
244
+ "rule": "locked_dimension",
245
+ "detail": tool_dimension,
246
+ "reason": (
247
+ f"Tool '{tool_name}' touches the '{tool_dimension}' "
248
+ f"dimension which the user explicitly locked in this "
249
+ f"brief."
250
+ ),
251
+ "suggestion": (
252
+ f"User locked this dimension. Either (a) surface the "
253
+ f"conflict and ask the user to unlock, or (b) pick a "
254
+ f"tool that operates on a different dimension. "
255
+ f"Available unlocked dimensions: "
256
+ f"{sorted(set(['structural', 'rhythmic', 'timbral', 'spatial']) - set(locked_dims))}."
257
+ ),
258
+ })
259
+
260
+ return {
261
+ "ok": not violations,
262
+ "violations": violations,
263
+ }
@@ -0,0 +1,72 @@
1
+ """Creative Director MCP tools — v1.18.3+ brief compliance.
2
+
3
+ Exposes `check_brief_compliance` as an MCP tool so the
4
+ `livepilot-creative-director` skill can call it before each risky
5
+ Phase 6 tool execution. Caller passes the compiled brief dict + the
6
+ intended tool call; the tool returns a violations report.
7
+
8
+ Stateless by design: no session storage of the active brief. The
9
+ director passes the brief each time. Full session-state active-brief
10
+ storage is v1.19 scope.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, Optional
16
+
17
+ from fastmcp import Context
18
+
19
+ from ..server import mcp
20
+ from .compliance import check_brief_compliance as _check_brief_compliance
21
+
22
+
23
+ @mcp.tool()
24
+ def check_brief_compliance(
25
+ ctx: Context,
26
+ brief: dict,
27
+ tool_name: str,
28
+ tool_args: Optional[dict] = None,
29
+ ) -> dict:
30
+ """Check whether an intended tool call complies with the active creative brief.
31
+
32
+ v1.18.3 #7 + #8 runtime enforcement for the director's anti_patterns
33
+ and locked_dimensions brief fields. Call this BEFORE executing any
34
+ risky tool from director's Phase 6 — especially when the brief has
35
+ non-empty anti_patterns or locked_dimensions.
36
+
37
+ brief: the compiled Creative Brief dict. May contain anti_patterns
38
+ (list of prose phrases), locked_dimensions (list of:
39
+ structural/rhythmic/timbral/spatial), reference_anchors, etc.
40
+ tool_name: the MCP tool name you're about to call.
41
+ tool_args: dict of arguments you'll pass to that tool.
42
+
43
+ Returns:
44
+ {
45
+ "ok": bool,
46
+ "violations": [
47
+ {
48
+ "rule": "anti_pattern" | "locked_dimension",
49
+ "detail": <the anti_pattern phrase OR the locked dimension>,
50
+ "reason": "Why this call appears to violate the brief",
51
+ "suggestion": "What to do about it",
52
+ },
53
+ ...
54
+ ],
55
+ }
56
+
57
+ Violations are NEVER automatic blocks — they're reports. The
58
+ director decides whether to proceed, surface to user, or abandon.
59
+ Empty brief (no anti_patterns, no locked_dimensions) always
60
+ returns ok=True.
61
+
62
+ Best-effort keyword heuristic, NOT semantic understanding. Will
63
+ miss subtle violations (e.g., 'too muddy' → 300 Hz cut needs
64
+ judgment this checker doesn't have). Will catch obvious ones
65
+ (e.g., 'bright top-end' → Hi Gain positive boost).
66
+ """
67
+ result = _check_brief_compliance(
68
+ brief=brief,
69
+ tool_name=tool_name,
70
+ tool_args=tool_args or {},
71
+ )
72
+ return result
@@ -301,6 +301,7 @@ from .stuckness_detector import tools as stuckness_tools # noqa: F401, E40
301
301
  from .wonder_mode import tools as wonder_mode_tools # noqa: F401, E402
302
302
  from .session_continuity import tools as session_cont_tools # noqa: F401, E402
303
303
  from .creative_constraints import tools as constraints_tools # noqa: F401, E402
304
+ from .creative_director import tools as creative_director_tools # noqa: F401, E402
304
305
  from .device_forge import tools as device_forge_tools # noqa: F401, E402
305
306
  from .sample_engine import tools as sample_engine_tools # noqa: F401, E402
306
307
  from .atlas import tools as atlas_tools # noqa: F401, E402
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.18.2",
3
+ "version": "1.18.3",
4
4
  "mcpName": "io.github.dreamrec/livepilot",
5
- "description": "Agentic production system for Ableton Live 12 — 427 tools, 52 domains. Device atlas (1305 devices), sample engine (Splice + browser + filesystem), auto-composition, spectral perception, technique memory, creative intelligence (12 engines)",
5
+ "description": "Agentic production system for Ableton Live 12 — 428 tools, 53 domains. Device atlas (1305 devices), sample engine (Splice + browser + filesystem), auto-composition, spectral perception, technique memory, creative intelligence (12 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.18.2"
8
+ __version__ = "1.18.3"
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": "427-tool agentic MCP production system for Ableton Live 12 — device atlas, sample engine, composer",
4
+ "description": "428-tool agentic MCP production system for Ableton Live 12 — device atlas, sample engine, composer",
5
5
  "repository": {
6
6
  "url": "https://github.com/dreamrec/LivePilot",
7
7
  "source": "github"
8
8
  },
9
- "version": "1.18.2",
9
+ "version": "1.18.3",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "livepilot",
14
- "version": "1.18.2",
14
+ "version": "1.18.3",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  }