livepilot 1.3.0 → 1.4.0
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 +13 -0
- package/README.md +94 -35
- package/bin/livepilot.js +28 -17
- package/mcp_server/connection.py +6 -3
- package/mcp_server/memory/__init__.py +5 -0
- package/mcp_server/memory/technique_store.py +301 -0
- package/mcp_server/server.py +47 -0
- package/mcp_server/tools/arrangement.py +11 -8
- package/mcp_server/tools/browser.py +5 -1
- package/mcp_server/tools/clips.py +8 -4
- package/mcp_server/tools/devices.py +11 -9
- package/mcp_server/tools/memory.py +198 -0
- package/mcp_server/tools/mixing.py +8 -4
- package/mcp_server/tools/notes.py +3 -1
- package/mcp_server/tools/tracks.py +8 -4
- package/mcp_server/tools/transport.py +6 -2
- package/package.json +2 -2
- package/plugin/agents/livepilot-producer/AGENT.md +5 -0
- package/plugin/commands/memory.md +22 -0
- package/plugin/plugin.json +4 -3
- package/plugin/skills/livepilot-core/SKILL.md +56 -8
- package/plugin/skills/livepilot-core/references/memory-guide.md +107 -0
- package/plugin/skills/livepilot-core/references/overview.md +16 -3
- package/remote_script/LivePilot/arrangement.py +28 -8
- package/remote_script/LivePilot/browser.py +26 -12
- package/remote_script/LivePilot/devices.py +4 -3
- package/remote_script/LivePilot/transport.py +3 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Memory MCP tools — technique library for saving, recalling, and replaying patterns.
|
|
2
|
+
|
|
3
|
+
8 tools for the agent's long-term memory system.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from fastmcp import Context
|
|
11
|
+
|
|
12
|
+
from ..server import mcp
|
|
13
|
+
from ..memory.technique_store import TechniqueStore
|
|
14
|
+
|
|
15
|
+
_store = TechniqueStore()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_store() -> TechniqueStore:
|
|
19
|
+
return _store
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@mcp.tool()
|
|
23
|
+
def memory_learn(
|
|
24
|
+
ctx: Context,
|
|
25
|
+
name: str,
|
|
26
|
+
type: str,
|
|
27
|
+
qualities: dict,
|
|
28
|
+
payload: dict,
|
|
29
|
+
tags: Optional[list] = None,
|
|
30
|
+
) -> dict:
|
|
31
|
+
"""Save a new technique to the memory library with stylistic qualities. type must be one of: beat_pattern, device_chain, mix_template, browser_pin, preference. qualities must include at minimum a 'summary' field."""
|
|
32
|
+
return _get_store().save(name=name, type=type, qualities=qualities, payload=payload, tags=tags)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@mcp.tool()
|
|
36
|
+
def memory_recall(
|
|
37
|
+
ctx: Context,
|
|
38
|
+
query: Optional[str] = None,
|
|
39
|
+
type: Optional[str] = None,
|
|
40
|
+
tags: Optional[list] = None,
|
|
41
|
+
limit: int = 10,
|
|
42
|
+
) -> dict:
|
|
43
|
+
"""Search the technique library by text query and/or filters. Returns summaries (no payload)."""
|
|
44
|
+
results = _get_store().search(query=query, type_filter=type, tags=tags, limit=limit)
|
|
45
|
+
return {"count": len(results), "techniques": results}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@mcp.tool()
|
|
49
|
+
def memory_get(ctx: Context, technique_id: str) -> dict:
|
|
50
|
+
"""Fetch a full technique by ID, including payload for replay."""
|
|
51
|
+
return _get_store().get(technique_id)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@mcp.tool()
|
|
55
|
+
def memory_replay(ctx: Context, technique_id: str, adapt: bool = False) -> dict:
|
|
56
|
+
"""Retrieve a technique with a replay plan for the agent to execute. adapt=false: returns step-by-step replay plan for exact reconstruction. adapt=true: returns technique for creative adaptation."""
|
|
57
|
+
store = _get_store()
|
|
58
|
+
technique = store.get(technique_id)
|
|
59
|
+
store.increment_replay(technique_id)
|
|
60
|
+
|
|
61
|
+
mode = "adapt" if adapt else "exact"
|
|
62
|
+
|
|
63
|
+
if adapt:
|
|
64
|
+
steps = [
|
|
65
|
+
"Read qualities and payload as inspiration",
|
|
66
|
+
"Create something new that matches the stylistic palette",
|
|
67
|
+
]
|
|
68
|
+
else:
|
|
69
|
+
steps = _generate_replay_steps(technique)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
"technique": technique,
|
|
73
|
+
"replay_plan": {
|
|
74
|
+
"mode": mode,
|
|
75
|
+
"type": technique["type"],
|
|
76
|
+
"steps": steps,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _generate_replay_steps(technique: dict) -> list[str]:
|
|
82
|
+
"""Generate human-readable replay steps based on technique type."""
|
|
83
|
+
t_type = technique["type"]
|
|
84
|
+
payload = technique.get("payload", {})
|
|
85
|
+
|
|
86
|
+
if t_type == "beat_pattern":
|
|
87
|
+
steps = []
|
|
88
|
+
kit = payload.get("kit_name")
|
|
89
|
+
if kit:
|
|
90
|
+
steps.append(f"Load kit '{kit}' using search_browser + load_browser_item")
|
|
91
|
+
steps.append(
|
|
92
|
+
f"Create a MIDI clip using create_clip "
|
|
93
|
+
f"(length={payload.get('clip_length', 4)} beats)"
|
|
94
|
+
)
|
|
95
|
+
notes = payload.get("notes", [])
|
|
96
|
+
if notes:
|
|
97
|
+
steps.append(f"Add {len(notes)} notes using add_notes with the stored note data")
|
|
98
|
+
tempo = payload.get("tempo")
|
|
99
|
+
if tempo:
|
|
100
|
+
steps.append(f"Set tempo to {tempo} BPM using set_tempo")
|
|
101
|
+
return steps or ["Replay the beat pattern from the stored payload"]
|
|
102
|
+
|
|
103
|
+
elif t_type == "device_chain":
|
|
104
|
+
steps = []
|
|
105
|
+
devices = payload.get("devices", [])
|
|
106
|
+
for i, dev in enumerate(devices):
|
|
107
|
+
dev_name = dev.get("name", f"device {i + 1}")
|
|
108
|
+
steps.append(f"Load '{dev_name}' using find_and_load_device")
|
|
109
|
+
params = dev.get("params", {})
|
|
110
|
+
if params:
|
|
111
|
+
steps.append(
|
|
112
|
+
f"Set {len(params)} parameters on '{dev_name}' using batch_set_parameters"
|
|
113
|
+
)
|
|
114
|
+
return steps or ["Load the device chain from the stored payload"]
|
|
115
|
+
|
|
116
|
+
elif t_type == "mix_template":
|
|
117
|
+
steps = []
|
|
118
|
+
returns = payload.get("returns", [])
|
|
119
|
+
if returns:
|
|
120
|
+
steps.append(
|
|
121
|
+
f"Create {len(returns)} return tracks using create_return_track"
|
|
122
|
+
)
|
|
123
|
+
for ret in returns:
|
|
124
|
+
devices = ret.get("devices", [])
|
|
125
|
+
for dev in devices:
|
|
126
|
+
dev_name = dev if isinstance(dev, str) else dev.get("name", "device")
|
|
127
|
+
steps.append(
|
|
128
|
+
f"Load '{dev_name}' on return track using find_and_load_device"
|
|
129
|
+
)
|
|
130
|
+
sends = payload.get("sends_pattern", {})
|
|
131
|
+
if sends:
|
|
132
|
+
steps.append(
|
|
133
|
+
"Apply send levels from sends_pattern "
|
|
134
|
+
"(note: role names must be resolved to track indices by the agent)"
|
|
135
|
+
)
|
|
136
|
+
return steps or ["Apply the mix template from the stored payload"]
|
|
137
|
+
|
|
138
|
+
elif t_type == "browser_pin":
|
|
139
|
+
uri = payload.get("uri", "")
|
|
140
|
+
name = payload.get("name", "item")
|
|
141
|
+
steps = [f"Load browser item '{name}' by URI '{uri}' using load_browser_item"]
|
|
142
|
+
return steps
|
|
143
|
+
|
|
144
|
+
elif t_type == "preference":
|
|
145
|
+
key = payload.get("key", "preference")
|
|
146
|
+
value = payload.get("value", "")
|
|
147
|
+
steps = [f"Apply preference '{key}' = '{value}'"]
|
|
148
|
+
return steps
|
|
149
|
+
|
|
150
|
+
return ["Replay the technique from the stored payload"]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@mcp.tool()
|
|
154
|
+
def memory_list(
|
|
155
|
+
ctx: Context,
|
|
156
|
+
type: Optional[str] = None,
|
|
157
|
+
tags: Optional[list] = None,
|
|
158
|
+
sort_by: str = "updated_at",
|
|
159
|
+
limit: int = 20,
|
|
160
|
+
) -> dict:
|
|
161
|
+
"""Browse the technique library with optional filtering."""
|
|
162
|
+
results = _get_store().list_techniques(
|
|
163
|
+
type_filter=type, tags=tags, sort_by=sort_by, limit=limit
|
|
164
|
+
)
|
|
165
|
+
return {"count": len(results), "techniques": results}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@mcp.tool()
|
|
169
|
+
def memory_favorite(
|
|
170
|
+
ctx: Context,
|
|
171
|
+
technique_id: str,
|
|
172
|
+
favorite: Optional[bool] = None,
|
|
173
|
+
rating: Optional[int] = None,
|
|
174
|
+
) -> dict:
|
|
175
|
+
"""Star and/or rate a technique (rating 0-5)."""
|
|
176
|
+
return _get_store().favorite(
|
|
177
|
+
technique_id=technique_id, favorite=favorite, rating=rating
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@mcp.tool()
|
|
182
|
+
def memory_update(
|
|
183
|
+
ctx: Context,
|
|
184
|
+
technique_id: str,
|
|
185
|
+
name: Optional[str] = None,
|
|
186
|
+
tags: Optional[list] = None,
|
|
187
|
+
qualities: Optional[dict] = None,
|
|
188
|
+
) -> dict:
|
|
189
|
+
"""Update name, tags, or qualities on an existing technique. Qualities are merged (lists replace)."""
|
|
190
|
+
return _get_store().update(
|
|
191
|
+
technique_id=technique_id, name=name, tags=tags, qualities=qualities
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@mcp.tool()
|
|
196
|
+
def memory_delete(ctx: Context, technique_id: str) -> dict:
|
|
197
|
+
"""Delete a technique from the library (creates backup first)."""
|
|
198
|
+
return _get_store().delete(technique_id)
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
8 tools matching the Remote Script mixing domain.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
6
10
|
from fastmcp import Context
|
|
7
11
|
|
|
8
12
|
from ..server import mcp
|
|
@@ -96,10 +100,10 @@ def get_track_routing(ctx: Context, track_index: int) -> dict:
|
|
|
96
100
|
def set_track_routing(
|
|
97
101
|
ctx: Context,
|
|
98
102
|
track_index: int,
|
|
99
|
-
input_type: str
|
|
100
|
-
input_channel: str
|
|
101
|
-
output_type: str
|
|
102
|
-
output_channel: str
|
|
103
|
+
input_type: Optional[str] = None,
|
|
104
|
+
input_channel: Optional[str] = None,
|
|
105
|
+
output_type: Optional[str] = None,
|
|
106
|
+
output_channel: Optional[str] = None,
|
|
103
107
|
) -> dict:
|
|
104
108
|
"""Set input/output routing for a track by display name. Use negative track_index for return tracks (-1=A, -2=B)."""
|
|
105
109
|
_validate_track_index(track_index)
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
14 tools matching the Remote Script tracks domain.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
6
10
|
from fastmcp import Context
|
|
7
11
|
|
|
8
12
|
from ..server import mcp
|
|
@@ -34,8 +38,8 @@ def get_track_info(ctx: Context, track_index: int) -> dict:
|
|
|
34
38
|
def create_midi_track(
|
|
35
39
|
ctx: Context,
|
|
36
40
|
index: int = -1,
|
|
37
|
-
name: str
|
|
38
|
-
color: int
|
|
41
|
+
name: Optional[str] = None,
|
|
42
|
+
color: Optional[int] = None,
|
|
39
43
|
) -> dict:
|
|
40
44
|
"""Create a new MIDI track. index=-1 appends at end."""
|
|
41
45
|
params = {"index": index}
|
|
@@ -53,8 +57,8 @@ def create_midi_track(
|
|
|
53
57
|
def create_audio_track(
|
|
54
58
|
ctx: Context,
|
|
55
59
|
index: int = -1,
|
|
56
|
-
name: str
|
|
57
|
-
color: int
|
|
60
|
+
name: Optional[str] = None,
|
|
61
|
+
color: Optional[int] = None,
|
|
58
62
|
) -> dict:
|
|
59
63
|
"""Create a new audio track. index=-1 appends at end."""
|
|
60
64
|
params = {"index": index}
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
12 tools matching the Remote Script transport domain.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
6
10
|
from fastmcp import Context
|
|
7
11
|
|
|
8
12
|
from ..server import mcp
|
|
@@ -68,8 +72,8 @@ def toggle_metronome(ctx: Context, enabled: bool) -> dict:
|
|
|
68
72
|
def set_session_loop(
|
|
69
73
|
ctx: Context,
|
|
70
74
|
enabled: bool,
|
|
71
|
-
start: float
|
|
72
|
-
length: float
|
|
75
|
+
start: Optional[float] = None,
|
|
76
|
+
length: Optional[float] = None,
|
|
73
77
|
) -> dict:
|
|
74
78
|
"""Set loop on/off and optional loop region (start beat, length in beats)."""
|
|
75
79
|
params = {"enabled": enabled}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livepilot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"mcpName": "io.github.dreamrec/livepilot",
|
|
5
|
-
"description": "AI copilot for Ableton Live 12 —
|
|
5
|
+
"description": "AI copilot for Ableton Live 12 — 104 MCP tools for music production, sound design, and mixing",
|
|
6
6
|
"author": "Pilot Studio",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"type": "commonjs",
|
|
@@ -17,6 +17,11 @@ You are LivePilot Producer — an autonomous music production agent for Ableton
|
|
|
17
17
|
Given a high-level description, you:
|
|
18
18
|
|
|
19
19
|
1. **Plan** — decide tempo, key, track layout, instrument choices, arrangement structure
|
|
20
|
+
1.5. **Consult memory** (unless user requests fresh exploration):
|
|
21
|
+
Call `memory_recall` with a query matching the task (limit=5).
|
|
22
|
+
Read the returned qualities and let them shape your plan — kit choices,
|
|
23
|
+
tempo range, rhythmic approach, sound palette. Don't copy — be influenced.
|
|
24
|
+
If the user says "fresh" / "ignore history" / "something new" → skip this step.
|
|
20
25
|
2. **Build tracks** — create and name tracks with appropriate colors
|
|
21
26
|
3. **Load instruments** — find and load the right synths, drum kits, and samplers
|
|
22
27
|
4. **HEALTH CHECK** — verify every track actually produces sound (see below)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory
|
|
3
|
+
description: Browse, search, and manage your saved technique library
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Show the user's technique memory library. Follow these steps:
|
|
7
|
+
|
|
8
|
+
1. Call `memory_list(limit=20)` to get an overview of saved techniques
|
|
9
|
+
2. Format as an organized list grouped by type:
|
|
10
|
+
- **Beats** — beat_pattern techniques
|
|
11
|
+
- **Device Chains** — device_chain techniques
|
|
12
|
+
- **Mix Templates** — mix_template techniques
|
|
13
|
+
- **Browser Pins** — browser_pin techniques
|
|
14
|
+
- **Preferences** — preference techniques
|
|
15
|
+
3. For each technique show: name, summary, rating (stars), favorite marker, tags
|
|
16
|
+
4. Show total count and breakdown by type
|
|
17
|
+
|
|
18
|
+
After presenting, ask if the user wants to:
|
|
19
|
+
- **Search** — "search for [query]" → use memory_recall
|
|
20
|
+
- **View details** — "show me [name]" → use memory_get
|
|
21
|
+
- **Delete** — "delete [name]" → use memory_delete (confirm first)
|
|
22
|
+
- **Rate** — "rate [name] 5 stars" → use memory_favorite
|
package/plugin/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livepilot",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "AI copilot for Ableton Live 12 —
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "AI copilot for Ableton Live 12 — 104 MCP tools for music production, sound design, and mixing",
|
|
5
5
|
"author": "Pilot Studio",
|
|
6
6
|
"skills": [
|
|
7
7
|
"skills/livepilot-core"
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"commands/session.md",
|
|
11
11
|
"commands/beat.md",
|
|
12
12
|
"commands/mix.md",
|
|
13
|
-
"commands/sounddesign.md"
|
|
13
|
+
"commands/sounddesign.md",
|
|
14
|
+
"commands/memory.md"
|
|
14
15
|
],
|
|
15
16
|
"agents": [
|
|
16
17
|
"agents/livepilot-producer"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: livepilot-core
|
|
3
|
-
description: Core discipline for controlling Ableton Live 12 through LivePilot's
|
|
3
|
+
description: Core discipline for controlling Ableton Live 12 through LivePilot's 104 MCP tools. Use whenever working with Ableton Live through MCP tools.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# LivePilot Core — Ableton Live 12 AI Copilot
|
|
7
7
|
|
|
8
|
-
LivePilot gives you
|
|
8
|
+
LivePilot gives you 104 MCP tools to control Ableton Live 12 in real-time: transport, tracks, clips, MIDI notes, devices, scenes, mixing, browser, arrangement, and technique memory.
|
|
9
9
|
|
|
10
10
|
## Golden Rules
|
|
11
11
|
|
|
@@ -14,10 +14,11 @@ LivePilot gives you 96 MCP tools to control Ableton Live 12 in real-time: transp
|
|
|
14
14
|
3. **Use `undo` liberally** — it's your safety net. Mention it to users when doing destructive ops
|
|
15
15
|
4. **One operation at a time** — don't batch unrelated changes. Verify between steps
|
|
16
16
|
5. **Track indices are 0-based** — track 0 is the first track. Use negative indices for return tracks (-1=A, -2=B). Use -1000 for master track.
|
|
17
|
-
6. **
|
|
18
|
-
7. **
|
|
19
|
-
8. **
|
|
20
|
-
9. **
|
|
17
|
+
6. **NEVER invent device/preset names** — always `search_browser` first, then use the exact `uri` from results with `load_browser_item`. Hallucinated names like "echomorph-hpf" will crash. The only exception is `find_and_load_device` for simple built-in effects ("Reverb", "Delay", "Compressor", "EQ Eight", "Saturator", "Utility").
|
|
18
|
+
7. **Color indices 0-69** — Ableton's fixed palette. Don't guess — use the index
|
|
19
|
+
8. **Volume is 0.0-1.0, pan is -1.0 to 1.0** — these are normalized, not dB
|
|
20
|
+
9. **Tempo range 20-999 BPM** — validated before sending to Ableton
|
|
21
|
+
10. **Always name your tracks and clips** — organization is part of the creative process
|
|
21
22
|
|
|
22
23
|
## Track Health Checks — MANDATORY
|
|
23
24
|
|
|
@@ -57,7 +58,7 @@ LivePilot gives you 96 MCP tools to control Ableton Live 12 in real-time: transp
|
|
|
57
58
|
- MIDI track with no instrument loaded
|
|
58
59
|
- Notes programmed but clip not fired
|
|
59
60
|
|
|
60
|
-
## Tool Domains (
|
|
61
|
+
## Tool Domains (104 total)
|
|
61
62
|
|
|
62
63
|
### Transport (12)
|
|
63
64
|
`get_session_info` · `set_tempo` · `set_time_signature` · `start_playback` · `stop_playback` · `continue_playback` · `toggle_metronome` · `set_session_loop` · `undo` · `redo` · `get_recent_actions` · `get_session_diagnostics`
|
|
@@ -86,6 +87,9 @@ LivePilot gives you 96 MCP tools to control Ableton Live 12 in real-time: transp
|
|
|
86
87
|
### Arrangement (19)
|
|
87
88
|
`get_arrangement_clips` · `create_arrangement_clip` · `add_arrangement_notes` · `get_arrangement_notes` · `remove_arrangement_notes` · `remove_arrangement_notes_by_id` · `modify_arrangement_notes` · `duplicate_arrangement_notes` · `transpose_arrangement_notes` · `set_arrangement_clip_name` · `set_arrangement_automation` · `back_to_arranger` · `jump_to_time` · `capture_midi` · `start_recording` · `stop_recording` · `get_cue_points` · `jump_to_cue` · `toggle_cue_point`
|
|
88
89
|
|
|
90
|
+
### Memory (8)
|
|
91
|
+
`memory_learn` · `memory_recall` · `memory_get` · `memory_replay` · `memory_list` · `memory_favorite` · `memory_update` · `memory_delete`
|
|
92
|
+
|
|
89
93
|
## Workflow: Building a Beat
|
|
90
94
|
|
|
91
95
|
1. `get_session_info` — check current state
|
|
@@ -146,15 +150,59 @@ Use `remove_notes_by_id` for surgical deletion.
|
|
|
146
150
|
Use `transpose_notes` for pitch shifting a region.
|
|
147
151
|
Use `quantize_clip` to snap notes to a grid (grid is an enum: 1=1/4, 2=1/8, 5=1/16, 8=1/32).
|
|
148
152
|
|
|
153
|
+
## Technique Memory
|
|
154
|
+
|
|
155
|
+
LivePilot has a persistent memory system for saving and recalling techniques — beats, device chains, mixing setups, browser pins, and preferences — with rich stylistic analysis.
|
|
156
|
+
|
|
157
|
+
### Three Modes of Operation
|
|
158
|
+
|
|
159
|
+
**Informed (default):** Before creative decisions, consult memory:
|
|
160
|
+
```
|
|
161
|
+
memory_recall(query relevant to the task, limit=5)
|
|
162
|
+
```
|
|
163
|
+
Read the qualities of returned techniques. Let them INFLUENCE your choices — instrument selection, parameter ranges, rhythmic density, harmonic language — but always create something new. The memory shapes your understanding of this user's taste, not a template to copy.
|
|
164
|
+
|
|
165
|
+
**Fresh (user override):** When the user signals a clean slate:
|
|
166
|
+
- "ignore my history" / "something completely new" / "fresh"
|
|
167
|
+
- "don't look at my saved stuff" / "surprise me"
|
|
168
|
+
→ Skip memory_recall entirely. Use only the shipped corpus and your own musical knowledge.
|
|
169
|
+
|
|
170
|
+
**Explicit Recall:** When the user references a saved technique:
|
|
171
|
+
- "use that boom bap beat" / "load my lo-fi chain" / "remember that thing I saved?"
|
|
172
|
+
→ `memory_recall` to find it → `memory_get` for full payload → `memory_replay` (adapt=false for exact, adapt=true for variation)
|
|
173
|
+
|
|
174
|
+
### Saving Techniques
|
|
175
|
+
|
|
176
|
+
When the user says "save this" / "remember this" / "I like this":
|
|
177
|
+
|
|
178
|
+
1. Collect raw data using existing tools (get_notes, get_device_parameters, etc.)
|
|
179
|
+
2. Write the qualities analysis — see `references/memory-guide.md` for the template
|
|
180
|
+
3. Call `memory_learn` with type, qualities, payload, tags
|
|
181
|
+
4. Confirm to the user what was saved and how it was characterized
|
|
182
|
+
|
|
183
|
+
### Memory Tools (8)
|
|
184
|
+
|
|
185
|
+
| Tool | What it does |
|
|
186
|
+
|------|-------------|
|
|
187
|
+
| `memory_learn` | Save a technique with qualities + payload |
|
|
188
|
+
| `memory_recall` | Search by text query, type, tags — returns summaries |
|
|
189
|
+
| `memory_get` | Fetch full technique by ID (with payload) |
|
|
190
|
+
| `memory_replay` | Get replay plan for agent to execute |
|
|
191
|
+
| `memory_list` | Browse library with filtering and sorting |
|
|
192
|
+
| `memory_favorite` | Star and/or rate (0-5) a technique |
|
|
193
|
+
| `memory_update` | Update name, tags, or qualities |
|
|
194
|
+
| `memory_delete` | Remove (creates backup first) |
|
|
195
|
+
|
|
149
196
|
## Reference Corpus
|
|
150
197
|
|
|
151
198
|
Deep production knowledge lives in `references/`. Consult these when making creative decisions — they contain specific parameter values, recipes, and patterns. Use them as starting points, not rigid rules.
|
|
152
199
|
|
|
153
200
|
| File | What's inside | When to consult |
|
|
154
201
|
|------|--------------|-----------------|
|
|
155
|
-
| `references/overview.md` | All
|
|
202
|
+
| `references/overview.md` | All 104 tools mapped with params, units, ranges | Quick lookup for any tool |
|
|
156
203
|
| `references/midi-recipes.md` | Drum patterns by genre, chord voicings, scales, hi-hat techniques, humanization, polymetrics | Programming MIDI notes, building beats |
|
|
157
204
|
| `references/sound-design.md` | Stock instruments/effects, parameter recipes for bass/pad/lead/pluck, device chain patterns | Loading and configuring devices |
|
|
158
205
|
| `references/mixing-patterns.md` | Gain staging, parallel compression, sidechain, EQ by instrument, bus processing, stereo width | Setting volumes, panning, adding effects |
|
|
159
206
|
| `references/ableton-workflow-patterns.md` | Session/Arrangement workflow, song structures by genre, follow actions, clip launch modes, export | Organizing sessions, structuring songs |
|
|
160
207
|
| `references/m4l-devices.md` | Browser organization, MIDI effects, rack systems, device loading patterns | Finding and loading devices, using racks |
|
|
208
|
+
| `references/memory-guide.md` | Qualities template, good/bad examples for each technique type | Saving techniques, writing qualities |
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Technique Memory Guide — Qualities Template & Examples
|
|
2
|
+
|
|
3
|
+
How to write rich, searchable stylistic analyses when saving techniques.
|
|
4
|
+
|
|
5
|
+
## The Qualities Template
|
|
6
|
+
|
|
7
|
+
Every technique gets an agent-written `qualities` object. All fields are optional
|
|
8
|
+
except `summary` (required). Fill what's relevant to the technique type.
|
|
9
|
+
|
|
10
|
+
| Field | What to write | Example |
|
|
11
|
+
|-------|--------------|---------|
|
|
12
|
+
| summary | One sentence — what this is and why it's good | "Dusty boom bap groove with lazy swing and ghost snares" |
|
|
13
|
+
| mood | 2-4 mood/feeling words | ["laid-back", "dusty", "head-nodding"] |
|
|
14
|
+
| genre_tags | Genre associations | ["boom-bap", "hip-hop", "lo-fi"] |
|
|
15
|
+
| rhythm_feel | How the groove feels — swing, syncopation, density | "Syncopated kick with lazy hat swing, ghost snares anticipate the backbeat" |
|
|
16
|
+
| harmonic_character | Key, scale, chord quality, movement | "C minor dorian, jazzy 7th chords, descending bass line" |
|
|
17
|
+
| sonic_texture | Timbral character — warm/bright/gritty/clean | "Dusty vinyl-crackle hats, boomy 808 kick, dry snare with room verb" |
|
|
18
|
+
| production_notes | When/how to use this, what it pairs with | "Works as verse beat, needs sparse melody on top — Rhodes or muted guitar" |
|
|
19
|
+
| reference_points | Artists, songs, styles it evokes | "J Dilla 'Donuts' era meets Madlib 'Madvillainy' drums" |
|
|
20
|
+
|
|
21
|
+
## Good vs Bad Qualities
|
|
22
|
+
|
|
23
|
+
### Beat Pattern
|
|
24
|
+
|
|
25
|
+
**GOOD:**
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"summary": "Dusty boom bap groove — lazy swing on the hats, ghost snares anticipate the backbeat, 85 BPM slow-roll energy",
|
|
29
|
+
"mood": ["laid-back", "dusty", "head-nodding"],
|
|
30
|
+
"genre_tags": ["boom-bap", "hip-hop"],
|
|
31
|
+
"rhythm_feel": "Syncopated kick at 0 and the 'and' of 1. Hi-hats on 8ths with +0.02 swing on offbeats. Ghost snares (vel 30) on 16ths before beats 2 and 4. The whole thing leans back.",
|
|
32
|
+
"production_notes": "Works as a verse beat. Needs sparse melody on top — Rhodes, muted guitar, or pitched sample. Leave headroom in low-mids for vocals.",
|
|
33
|
+
"reference_points": "J Dilla 'Donuts' era meets Madlib on 'Madvillainy'"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**BAD:**
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"summary": "Hip hop beat at 85 BPM with kick, snare, and hi-hats"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
The bad version is factual but tells the agent nothing about *feel*. It can't distinguish this from any other hip-hop beat.
|
|
44
|
+
|
|
45
|
+
### Device Chain
|
|
46
|
+
|
|
47
|
+
**GOOD:**
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"summary": "Warm tape-style lo-fi chain — subtle saturation into gentle filtering, makes anything sound like it's playing through a dusty speaker",
|
|
51
|
+
"mood": ["warm", "nostalgic", "lo-fi"],
|
|
52
|
+
"sonic_texture": "Soft Sine saturation adds even harmonics without harshness. Auto Filter rolls off highs gently around 3kHz. Erosion adds subtle digital artifacts like worn tape. The chain darkens and warms without killing presence.",
|
|
53
|
+
"production_notes": "Put this on Rhodes, guitar samples, or pads. Not great for drums — kills transients. Works beautifully on chord progressions.",
|
|
54
|
+
"reference_points": "Lo-fi hip-hop study beats aesthetic, Nujabes-style warmth"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**BAD:**
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"summary": "Saturator then Auto Filter then Erosion"
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Mix Template
|
|
66
|
+
|
|
67
|
+
**GOOD:**
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"summary": "Deep house return setup — long lush reverb on A, filtered ping-pong delay on B, subtle parallel compression on C",
|
|
71
|
+
"mood": ["spacious", "deep", "hypnotic"],
|
|
72
|
+
"genre_tags": ["deep-house", "tech-house"],
|
|
73
|
+
"sonic_texture": "Reverb is dark and long (4s decay, heavy high-cut) for depth without brightness. Delay is filtered (LP at 3kHz) so echoes sit behind the mix. Parallel compression adds density to drums without crushing transients.",
|
|
74
|
+
"production_notes": "Send drums to C at 0.3, pads to A at 0.5, synth stabs to B at 0.3. Keep kick dry (no sends). Return levels around -8dB for subtlety."
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Preference
|
|
79
|
+
|
|
80
|
+
**GOOD:**
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"summary": "Always use Valhalla VintageVerb instead of stock Reverb on return tracks — stock Reverb sounds too metallic in the highs for my taste"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Browser Pin
|
|
88
|
+
|
|
89
|
+
**GOOD:**
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"summary": "808 Core Kit — my go-to drum kit for trap and hip-hop. Has a punchy kick that sits well with Saturator, crispy hats, and a tight clap."
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## When to Save
|
|
97
|
+
|
|
98
|
+
- User says "save this" / "remember this" / "I like this"
|
|
99
|
+
- A beat, sound, or chain turns out particularly well
|
|
100
|
+
- User discovers a browser item they want to use again
|
|
101
|
+
- User states a preference about how they work
|
|
102
|
+
|
|
103
|
+
## When NOT to Save
|
|
104
|
+
|
|
105
|
+
- Generic, unfinished, or placeholder work
|
|
106
|
+
- Things that are already in the shipped reference corpus
|
|
107
|
+
- Exact duplicates of existing saved techniques
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LivePilot Architecture & Tool Reference
|
|
2
2
|
|
|
3
|
-
LivePilot is an MCP server that controls Ableton Live 12 in real-time through
|
|
3
|
+
LivePilot is an MCP server that controls Ableton Live 12 in real-time through 104 tools across 10 domains. This document maps every tool to what it actually does in Ableton, so you know exactly which tool to reach for.
|
|
4
4
|
|
|
5
5
|
## Architecture
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ Claude Code ──MCP──► FastMCP Server ──TCP/9878──► Remote
|
|
|
14
14
|
- **Protocol**: JSON over TCP, newline-delimited. Every command gets a response.
|
|
15
15
|
- **Thread safety**: All Live Object Model (LOM) access happens on Ableton's main thread
|
|
16
16
|
|
|
17
|
-
## The
|
|
17
|
+
## The 104 Tools — What Each One Does
|
|
18
18
|
|
|
19
19
|
### Transport (12) — Playback, tempo, global state, diagnostics
|
|
20
20
|
|
|
@@ -142,7 +142,7 @@ Claude Code ──MCP──► FastMCP Server ──TCP/9878──► Remote
|
|
|
142
142
|
| `get_browser_tree` | Returns top-level browser categories | — |
|
|
143
143
|
| `get_browser_items` | Lists items in a browser path | `path` |
|
|
144
144
|
| `search_browser` | Searches the browser | `query` |
|
|
145
|
-
| `load_browser_item` | Loads a browser item onto a track | `track_index`, `uri` |
|
|
145
|
+
| `load_browser_item` | Loads a browser item onto a track — **`uri` MUST come from `search_browser` results, NEVER invented** | `track_index`, `uri` |
|
|
146
146
|
|
|
147
147
|
### Arrangement (19) — Timeline, recording, cue points, arrangement notes
|
|
148
148
|
|
|
@@ -168,6 +168,19 @@ Claude Code ──MCP──► FastMCP Server ──TCP/9878──► Remote
|
|
|
168
168
|
| `jump_to_cue` | Jumps to a cue point by index | `cue_index` |
|
|
169
169
|
| `toggle_cue_point` | Creates/removes cue point at current position | — |
|
|
170
170
|
|
|
171
|
+
### Memory (8) — Technique library persistence
|
|
172
|
+
|
|
173
|
+
| Tool | What it does | Key params |
|
|
174
|
+
|------|-------------|------------|
|
|
175
|
+
| `memory_learn` | Saves a technique with stylistic qualities | `name`, `type`, `qualities`, `payload`, `tags` |
|
|
176
|
+
| `memory_recall` | Searches library by text and filters | `query`, `type`, `tags`, `limit` |
|
|
177
|
+
| `memory_get` | Fetches full technique including payload | `technique_id` |
|
|
178
|
+
| `memory_replay` | Returns technique with replay plan for agent | `technique_id`, `adapt` (bool) |
|
|
179
|
+
| `memory_list` | Browses library with filtering/sorting | `type`, `tags`, `sort_by`, `limit` |
|
|
180
|
+
| `memory_favorite` | Stars and/or rates a technique | `technique_id`, `favorite`, `rating` (0-5) |
|
|
181
|
+
| `memory_update` | Updates name, tags, or qualities | `technique_id`, `name`, `tags`, `qualities` |
|
|
182
|
+
| `memory_delete` | Removes technique (backs up first) | `technique_id` |
|
|
183
|
+
|
|
171
184
|
## Units & Ranges Quick Reference
|
|
172
185
|
|
|
173
186
|
| Concept | Unit/Range | Notes |
|