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.
@@ -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 | None = None,
100
- input_channel: str | None = None,
101
- output_type: str | None = None,
102
- output_channel: str | None = None,
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,8 +3,10 @@
3
3
  8 tools matching the Remote Script notes domain.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import json
7
- from typing import Any
9
+ from typing import Any, Optional
8
10
 
9
11
  from fastmcp import Context
10
12
 
@@ -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 | None = None,
38
- color: int | None = None,
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 | None = None,
57
- color: int | None = None,
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 | None = None,
72
- length: float | None = None,
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.0",
3
+ "version": "1.4.0",
4
4
  "mcpName": "io.github.dreamrec/livepilot",
5
- "description": "AI copilot for Ableton Live 12 — 96 MCP tools for music production, sound design, and mixing",
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.3.0",
4
- "description": "AI copilot for Ableton Live 12 — 96 MCP tools for music production, sound design, and mixing",
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 96 MCP tools. Use whenever working with Ableton Live through MCP tools.
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 96 MCP tools to control Ableton Live 12 in real-time: transport, tracks, clips, MIDI notes, devices, scenes, mixing, browser, and arrangement.
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. **Color indices 0-69** — Ableton's fixed palette. Don't guess use the index
18
- 7. **Volume is 0.0-1.0, pan is -1.0 to 1.0**these are normalized, not dB
19
- 8. **Tempo range 20-999 BPM** — validated before sending to Ableton
20
- 9. **Always name your tracks and clips** — organization is part of the creative process
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 guessuse 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 (96 total)
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 96 tools mapped with params, units, ranges | Quick lookup for any tool |
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 96 tools across 9 domains. This document maps every tool to what it actually does in Ableton, so you know exactly which tool to reach for.
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 96 Tools — What Each One Does
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 |