@mthines/reaper-mcp 0.19.0 → 0.70.2

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.
Files changed (116) hide show
  1. package/README.md +19 -570
  2. package/bridge-ui/mcp_bridge.html +129 -0
  3. package/bridge-ui/mcp_bridge.webmanifest +16 -0
  4. package/bridge-ui/mcp_bridge_icon_192.png +0 -0
  5. package/bridge-ui/mcp_bridge_icon_512.png +0 -0
  6. package/bridge-ui/mcp_bridge_sw.js +35 -0
  7. package/claude/agents/plugin-researcher.md +188 -0
  8. package/claude/knowledge/reference/aesthetics-scoring.md +48 -0
  9. package/{knowledge → claude/knowledge}/reference/common-mistakes.md +1 -1
  10. package/claude/knowledge/reference/lorekit-setup.md +36 -0
  11. package/claude/knowledge/reference/memory-protocol.md +377 -0
  12. package/{knowledge → claude/knowledge}/reference/metering.md +5 -5
  13. package/claude/knowledge/reference/perceived-loudness.md +182 -0
  14. package/{knowledge → claude/knowledge}/workflows/editing.md +4 -0
  15. package/{knowledge → claude/knowledge}/workflows/gain-staging.md +21 -23
  16. package/{knowledge → claude/knowledge}/workflows/learn-plugin.md +15 -48
  17. package/{knowledge → claude/knowledge}/workflows/master-bus.md +13 -1
  18. package/claude/knowledge/workflows/section-levels.md +138 -0
  19. package/{knowledge → claude/knowledge}/workflows/session-prep.md +4 -0
  20. package/claude/knowledge/workflows/transient-lighting.md +52 -0
  21. package/claude/skills/critique/SKILL.md +131 -0
  22. package/claude/skills/editing/SKILL.md +281 -0
  23. package/claude/skills/learn-plugin/SKILL.md +210 -0
  24. package/claude/skills/mastering/SKILL.md +151 -0
  25. package/claude/skills/mix-memory/SKILL.md +140 -0
  26. package/claude/skills/mixer/SKILL.md +253 -0
  27. package/claude/skills/new-extension/SKILL.md +324 -0
  28. package/main.js +7843 -1940
  29. package/package.json +17 -15
  30. package/reaper/CLAUDE.md +22 -4
  31. package/reaper/mcp_actions_lib.lua +375 -0
  32. package/reaper/mcp_analyzer.jsfx +27 -12
  33. package/reaper/mcp_arrange_lib.lua +949 -0
  34. package/reaper/mcp_bridge.lua +2321 -758
  35. package/reaper/mcp_edit_views_lib.lua +1378 -0
  36. package/reaper/mcp_envelopes_lib.lua +748 -0
  37. package/reaper/mcp_extensions_lib.lua +55 -0
  38. package/reaper/mcp_fxstate_lib.lua +144 -0
  39. package/reaper/mcp_gain_trace.jsfx +126 -0
  40. package/reaper/mcp_items_lib.lua +877 -0
  41. package/reaper/mcp_lufs_meter.jsfx +16 -13
  42. package/reaper/mcp_midi_lib.lua +555 -0
  43. package/reaper/mcp_mixing_lib.lua +1021 -0
  44. package/reaper/mcp_plan_lib.lua +801 -0
  45. package/reaper/mcp_prefs_lib.lua +127 -0
  46. package/reaper/mcp_project_lib.lua +1088 -0
  47. package/reaper/mcp_recording_lib.lua +595 -0
  48. package/reaper/mcp_render_lib.lua +492 -0
  49. package/reaper/mcp_snapshot_lib.lua +547 -120
  50. package/reaper/mcp_snapshot_next.lua +10 -4
  51. package/reaper/mcp_snapshot_prev.lua +11 -4
  52. package/reaper/mcp_snapshot_quick_save.lua +7 -32
  53. package/reaper/mcp_snapshots_ui_lib.lua +258 -0
  54. package/reaper/mcp_tracks_lib.lua +409 -0
  55. package/sidecar/analysis.py +661 -0
  56. package/sidecar/chords.py +96 -0
  57. package/sidecar/mixcheck.py +295 -0
  58. package/sidecar/requirements-chords.txt +6 -0
  59. package/sidecar/requirements-separation.txt +3 -0
  60. package/sidecar/requirements.txt +17 -0
  61. package/sidecar/separation.py +142 -0
  62. package/sidecar/server.py +622 -0
  63. package/sidecar/tests/test_analysis.py +249 -0
  64. package/sidecar/tests/test_chords.py +117 -0
  65. package/sidecar/tests/test_mixcheck.py +163 -0
  66. package/sidecar/tests/test_separation.py +73 -0
  67. package/sidecar/tests/test_server.py +464 -0
  68. package/sidecar/tests/test_verify.py +243 -0
  69. package/sidecar/tests/test_voice_render.py +268 -0
  70. package/sidecar/tests/test_voice_sketch.py +140 -0
  71. package/sidecar/verify.py +224 -0
  72. package/sidecar/voice_render.py +295 -0
  73. package/sidecar/voice_sketch.py +280 -0
  74. package/claude-agents/critique.md +0 -147
  75. package/claude-agents/editor.md +0 -184
  76. package/claude-agents/levels.md +0 -107
  77. package/claude-agents/mastering.md +0 -129
  78. package/claude-agents/mixer.md +0 -248
  79. package/claude-agents/preflight.md +0 -149
  80. package/claude-agents/producer.md +0 -159
  81. package/claude-agents/setup.md +0 -150
  82. package/claude-agents/stems.md +0 -135
  83. package/claude-rules/architecture.md +0 -39
  84. package/claude-rules/development.md +0 -54
  85. package/claude-rules/lua-bridge.md +0 -50
  86. package/claude-rules/testing.md +0 -42
  87. package/claude-skills/learn-plugin.md +0 -123
  88. package/knowledge/CLAUDE.md +0 -71
  89. package/knowledge/plugins/_template.md +0 -82
  90. package/knowledge/plugins/fabfilter/pro-c-2.md +0 -117
  91. package/knowledge/plugins/fabfilter/pro-l-2.md +0 -95
  92. package/knowledge/plugins/fabfilter/pro-q-3.md +0 -112
  93. package/knowledge/plugins/neural-dsp/helix-native.md +0 -104
  94. package/knowledge/plugins/stock-reaper/js-1175-compressor.md +0 -94
  95. package/knowledge/plugins/stock-reaper/rea-comp.md +0 -100
  96. package/knowledge/plugins/stock-reaper/rea-delay.md +0 -95
  97. package/knowledge/plugins/stock-reaper/rea-eq.md +0 -103
  98. package/knowledge/plugins/stock-reaper/rea-gate.md +0 -99
  99. package/knowledge/plugins/stock-reaper/rea-limit.md +0 -75
  100. package/knowledge/plugins/stock-reaper/rea-verb.md +0 -76
  101. package/knowledge/reference/perceived-loudness.md +0 -122
  102. package/reaper/mcp_snapshot_manager.lua +0 -1001
  103. /package/{knowledge → claude/knowledge}/genres/_template.md +0 -0
  104. /package/{knowledge → claude/knowledge}/genres/electronic.md +0 -0
  105. /package/{knowledge → claude/knowledge}/genres/hip-hop.md +0 -0
  106. /package/{knowledge → claude/knowledge}/genres/metal.md +0 -0
  107. /package/{knowledge → claude/knowledge}/genres/orchestral.md +0 -0
  108. /package/{knowledge → claude/knowledge}/genres/pop.md +0 -0
  109. /package/{knowledge → claude/knowledge}/genres/rock.md +0 -0
  110. /package/{knowledge → claude/knowledge}/reference/compression.md +0 -0
  111. /package/{knowledge → claude/knowledge}/reference/frequencies.md +0 -0
  112. /package/{knowledge → claude/knowledge}/workflows/delivery.md +0 -0
  113. /package/{knowledge → claude/knowledge}/workflows/drum-bus.md +0 -0
  114. /package/{knowledge → claude/knowledge}/workflows/low-end.md +0 -0
  115. /package/{knowledge → claude/knowledge}/workflows/stem-prep.md +0 -0
  116. /package/{knowledge → claude/knowledge}/workflows/vocal-chain.md +0 -0
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: editing
3
+ description: >
4
+ Edits a live REAPER session through the reaper MCP tools: MIDI parts (writing,
5
+ rewriting, quantizing, importing), arrangement (split, move, copy, insert or
6
+ remove time), timing and phase, crossfades and comping, voice recordings into
7
+ arrangements, audio stem separation, and A/B-testing variations in fixed lanes.
8
+ Changes notes and items, not levels or FX; use /mixer for those. Use when asked
9
+ to edit, rewrite, tighten, comp, change the groove, compare parts, turn humming
10
+ or beatboxing into music, or split a recording into stems. Triggers on "edit
11
+ the drums", "change the chorus", "make a variation", "A/B these takes",
12
+ "comp this", "tighten the timing", "compose from this recording", "turn my
13
+ humming into a song", "split stems", "/editing".
14
+ argument-hint: '[what to edit, voice recording, stems, or versions to compare]'
15
+ license: MIT
16
+ metadata:
17
+ author: mthines
18
+ version: '1.0.0'
19
+ workflow_type: applied
20
+ tags:
21
+ - editing
22
+ - midi
23
+ - arrangement
24
+ - comping
25
+ - reaper
26
+ ---
27
+
28
+ # Editing
29
+
30
+ Edit the notes, items and structure of a **live** REAPER session through the
31
+ `reaper` MCP tools. This skill changes what plays and when. Levels, EQ,
32
+ compression and the master belong to `/mixer` and `/mastering`; what a sampled
33
+ instrument expects (note map, keyswitches) comes from `/learn-plugin`'s LoreKit
34
+ record. After an edit, hand the balance question to `/mixer`.
35
+
36
+ The step-by-step procedures (crossfades, phase, stretch markers, head and tail
37
+ cleanup, arrangement edits) are in `knowledge/workflows/editing.md`; load it for
38
+ audio cleanup. Voice sketches and stem separation use the workflows below, not
39
+ the recorded-track cleanup procedure.
40
+
41
+ ## Rules that save sessions
42
+
43
+ 1. **Re-list before every index-based write.** The user edits the session while
44
+ you work: a deleted or added track moves every index after it (this once put
45
+ an EQ on the wrong tracks). `list_tracks` (filtered by `parent`) or
46
+ `get_track_lanes` right before each batch, and target by name where it is
47
+ unique. Item indexes also change after every move, import or delete.
48
+ 2. **Snapshots do not store items.** `snapshot_save` keeps faders and FX
49
+ parameters, so it cannot undo a MIDI or arrangement edit. Before changing
50
+ items, keep the original as a **take** of the item it replaces (see "Keeping
51
+ the original" below), or as the A lane of a lane pair. **Never mute an
52
+ original and leave it under or beside the new item**: overlapping muted items
53
+ clutter the timeline and are easy to leave muted. Delete the original only
54
+ when the user says the new version won.
55
+ 3. **Keep the user's selection in mind.** `set_selected_items` and item actions
56
+ replace it; say so when it ends up changed.
57
+ 4. **Validate, then write.** Check pitch range, track and item before the first
58
+ write. A MIDI write that fails halfway is undone by the server; a bad import
59
+ can still leave an item you did not want, so list items after.
60
+ 5. **Check the instrument before writing MIDI.** A sampled instrument has note
61
+ ranges and keyswitch zones (Odin x Ari Lite: notes below 36 are keyswitches,
62
+ so music written there is silent or switches articulation). Read the plugin's
63
+ record (`get_builtin_knowledge`, `memory.read` of `user::plugins::…`) before
64
+ writing a part, and probe one note if it is unverified.
65
+ 6. **Plugin gate — no plugin is touched before its memory is read.** Before the
66
+ first call that adds, sets, loads a preset for, writes MIDI to, or reads parameters
67
+ of a plugin (`add_fx`, `setup_fx_chain`, `set_fx_parameter`,
68
+ `set_multiple_fx_parameters`, `set_fx_preset`, `load_fx_chain`, MIDI for an
69
+ instrument track, take FX), look it up — every plugin, every time it is new to this
70
+ session, including ones the user named, ones already in the project and ones you
71
+ only meet while listing a chain. Never skip it because the plugin looks familiar.
72
+ Look up both layers: `list_builtin_knowledge { query: "<plugin name>" }` (or `tags:
73
+ ["fx::<FX name>"]`) / `get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }`,
74
+ and `memory.search` / `memory.read` of `user::plugins::{vendor}/{plugin}` (the user's
75
+ record wins). Then **follow the record**: its MIDI map and note ranges, parameter
76
+ scaling, recommended settings and gotchas decide what you do, and a setting you were
77
+ about to use that the record warns against is not used. Say it in one chat line
78
+ ("Recalled Odin x Ari Lite: notes <36 are keyswitches → transposing"). Keep a running
79
+ list of recalled plugins and don't re-read those. No record in either layer: say so
80
+ and carry on (or bootstrap it when the user asked for the plugin by name). LoreKit
81
+ not connected: say so once and use the built-in read only.
82
+
83
+ ## Writing and rewriting MIDI
84
+
85
+ - **Fast path for a whole part:** generate one `.mid` per instrument with a node
86
+ script (480 PPQ, a tempo and 4/4 meta event, an end-of-track at the last bar
87
+ line), then `import_midi_file { path, trackIndex, position }`. Thousands of
88
+ `insert_midi_note` calls are far slower. The file's tempo is **not** applied:
89
+ set the project tempo first.
90
+ - **Drum maps are not General MIDI.** Check the kit's record (GGD Invasion: kick
91
+ R24/L23, snare 26, toms 33-38, hats 43/45, crash L52, china 65). Alternate kick
92
+ feet when two hits are a 16th apart.
93
+ - **Small changes:** `edit_midi_notes` / `insert_midi_notes` (batch),
94
+ `transform_midi` (transpose, velocity, humanize, length) and `quantize_midi`
95
+ (grid, strength, swing). Positions are in beats, velocity 1-127.
96
+ - **Replacing a section:** import the new section at its start time on the same
97
+ track, then fold old and new into one item of takes (below) until approved.
98
+ Imported items never overwrite existing ones.
99
+ - **Keeping the original (takes, never mute).** For one section replaced:
100
+ 1. `set_selected_items` on exactly the old and new item of **one** section,
101
+ then `run_action 40543` ("Take: Implode items on same track into takes").
102
+ Do one section per call: selecting several sections at once merges them
103
+ all into a single item (seen live; `undo_project` reverts it). Work from
104
+ the highest item index down, since indexes shift after each implode.
105
+ 2. The takes keep the lower-indexed item first. `list_takes` the item, then
106
+ `set_active_take` the version that should play (`takeIndex` 1 when the
107
+ new item came after the old one).
108
+ 3. The imploded item can inherit the mute: `get_media_item_properties`, and if
109
+ `muted`, `set_media_item_properties { mute: 0 }` (the parameter is `mute`,
110
+ a number 0/1, not a boolean).
111
+ 4. Switch versions later with `set_active_take`; when the user decides, delete
112
+ the losing take (or keep it). Take names are blank for imported items; say
113
+ which take is which in chat.
114
+ Use fixed lanes below instead when whole-song versions are compared.
115
+ - **Big MIDI calls can hit the 10 s bridge timeout** (seen on a 400-note
116
+ `transform_midi` while the user was in the session). Prefer re-importing a
117
+ generated file over editing hundreds of notes in place.
118
+
119
+ ## Voice recordings to a playable arrangement
120
+
121
+ For "make music from this humming/beatboxing", use `transcribe_voice_sketch`.
122
+ Do not substitute a hand-written melody or a generic MIDI script for analyzing
123
+ the recording. File analysis/export does not require REAPER; importing and
124
+ playing the result requires a live bridge.
125
+
126
+ 1. **Locate and protect the source.** Use an absolute path on the machine running
127
+ the MCP server. Download an attachment there first; a cloud attachment or an
128
+ orb path is not automatically accessible to a local server. Keep the original
129
+ file unchanged. Select the musical range with `startTime`/`endTime` to exclude
130
+ speech, count-ins and long silence, at most 120 seconds per call.
131
+ 2. **Analyze before importing.** Start with `limit: 0` and no `outputPath` for
132
+ summaries, warnings, tempo and key. Use `mode: auto` for mixed humming and
133
+ beatboxing, `melody` for humming alone, `drums` for beatboxing alone. The core
134
+ sidecar is sufficient; no pitch model or Demucs install is needed. If the
135
+ tool is missing, check the server build/connection rather than inventing an
136
+ alternative implementation. Missing core setup:
137
+ `reaper-mcp setup-sidecar --without-aesthetics`.
138
+ 3. **Resolve musical uncertainty.** Ordinary timing drift becomes one rounded
139
+ tempo. Automatic changes need two adjacent four-second windows and at least
140
+ 20% difference by default; exact half/double-time changes remain ambiguous.
141
+ If the pulse is uncertain, use the user's BPM or offer short auditions of
142
+ plausible pulses, then rerun with `bpm` to fix the chosen tempo. Never reuse
143
+ a previous recording's BPM as a default. Meter is assumed 4/4 and the first
144
+ onset is beat zero, not a detected downbeat. Report weak key confidence or a
145
+ fallback key; do not force the melody into it. `key` overrides accompaniment
146
+ only. For missed low/short syllables, try a lower `pitchMin` or `minNoteMs`
147
+ down to 40, explaining the increased false-note risk. If recognition remains
148
+ poor, ask for a cleaner take or separate humming and beatboxing takes.
149
+ 4. **Export the requested draft.** Use `arrange: true` for generated drums, bass,
150
+ chords and repeated detected melody, default 16 bars. Use `arrange: false`
151
+ for detected melody/percussion only. `mode` limits extraction, not the
152
+ generated backing parts. Backbeats, fills, chords and song
153
+ sections are proposals, not recovered performances. Choose a new absolute
154
+ `.mid` `outputPath` under an existing folder. Export includes every note
155
+ regardless of response pagination. With separate takes, extract each in its
156
+ own mode with a shared BPM/grid and combine once; do not stack two complete
157
+ generated backing bands. Align takes using a known cue or ask for their
158
+ offset; each take's first onset becomes its own beat zero.
159
+ 5. **Set tempo before MIDI import.** Inspect `get_tempo_map` and existing items.
160
+ In an empty project starting at zero, apply `arrangement.tempos` for the full
161
+ generated score, or `tempo.segments` for transcription-only output. Use
162
+ `set_project_tempo` for the first BPM and `add_tempo_marker` with
163
+ `timeSigNumerator: 4`, `timeSigDenominator: 4`, `linear: false` at zero to
164
+ establish 4/4; use `linear: false` for later changes too. Convert segment
165
+ beats to project seconds by integrating the preceding BPM segments, not by
166
+ using the initial BPM throughout. Source `time`/`originSeconds` are original file times, not marker
167
+ positions for the exported score. Preserve an existing project's tempo map
168
+ by default; resolve a mismatch with the user before changing it. Then
169
+ `import_midi_file { path, newTracks: true, trackIndex, position }` creates one
170
+ named track per part. Re-list immediately before choosing `trackIndex`.
171
+ The importer applies neither the file tempo map nor GM program changes.
172
+ 6. **Make it audible.** Hand instrument/FX setup to `/mixer`: choose installed
173
+ drum, bass, chord and lead instruments and check their knowledge records.
174
+ The exported drum part is GM on MIDI channel 10; verify the kit's channel
175
+ handling and map, then remap notes when necessary. Do not transpose all drum
176
+ notes as a melodic part. Check melody/bass ranges and keyswitches too. A
177
+ successful MIDI import is not proof of audible playback.
178
+ 7. **Verify a short section first.** Read back the imported notes, tempo map and
179
+ track placement, then play a representative groove and melody for the user.
180
+ Check audible output through `/mixer` and ask whether the pulse, melody and
181
+ drum roles match the idea. Fix octaves, false notes and drum mapping before
182
+ polishing or extending. Keep variants in fixed lanes and compare them at a
183
+ shared project tempo; use separate projects or rendered WAVs for different
184
+ tempo maps. Report what was detected, what was generated and what is unsure.
185
+
186
+ ## Stem splitting: choose the right operation
187
+
188
+ - **Mixed voice sketch:** start with `transcribe_voice_sketch` directly. Pitch
189
+ and percussion are analyzed independently, including overlapping events.
190
+ Do not run Demucs first by default. Its accuracy on humming plus beatboxing
191
+ is unverified; if explicitly tried, keep a direct-transcription baseline and
192
+ audition both before discarding anything.
193
+ - **Recorded band or song:** use `separate_stems` for audio source separation.
194
+ `htdemucs` gives drums, bass, other and vocals; `htdemucs_6s` also gives guitar
195
+ and piano. Neither splits kick/snare/hat. Requires the opt-in
196
+ `reaper-mcp setup-sidecar --with-separation`; the six-source model downloads
197
+ weights on first use. Explain missing dependencies/downloads before setup.
198
+ Choose an explicit range, at most 600 seconds, and a fresh `outDir`. A track
199
+ input is rendered post-FX; use its original file only when that is the wanted
200
+ source. Leave the source untouched and listen for bleed and artifacts before
201
+ relying on a separated stem.
202
+ - **Generated instrument WAVs:** `transcribe_voice_sketch` with `outputPath`
203
+ plus `soundfontPath` renders a mix and instrument stems. These are
204
+ resynthesized instruments, not isolated original voice audio. This optional
205
+ route needs local FluidSynth and the user's GM `.sf2`, with at most 240
206
+ seconds including release tail. Prefer MIDI plus installed instruments when
207
+ those dependencies are absent. A `preview.error` can accompany a successful
208
+ MIDI export; keep that file and do not retry the same existing output path.
209
+ - **Individual generated drum parts:** the tool exports one drum MIDI part and
210
+ one `drums.wav`, not separate kit-piece WAVs. If requested, split the generated
211
+ GM drum notes by pitch into kick, snare, hat and other MIDI parts before
212
+ instrument-specific remapping. Keep a shared origin and tempo, preserve
213
+ velocities, and mute the unsplit copy when playing the split parts. Separate
214
+ audio outputs need a verified kit-output setup or separate renders; delegate
215
+ that routing/render setup to `/mixer`. Never label these as isolated beatbox
216
+ audio.
217
+
218
+ For Demucs insertion, `insertTracks: true` creates a **muted folder**. A track's
219
+ stems start at `startTime`; a file's start at `filePosition + startTime`, where
220
+ `filePosition` is the project position of the source file's second zero. Inspect
221
+ returned `inserted`/`warning` and re-list tracks before retrying; files can exist
222
+ even if insertion failed. For generated WAVs, use `insert_audio_file` to place
223
+ every instrument stem at the same chosen project position. Play either the
224
+ source/mix or the stem set, not both. Check parent mute and solo states when a
225
+ stem seems silent; preserve the source and make A/B switching explicit.
226
+
227
+ ## A/B-testing MIDI or arrangement variants (fixed lanes)
228
+
229
+ Use this to compare alternatives that change notes or arrangement: a drum
230
+ groove, a bass line, a different chorus. A snapshot cannot switch them (rule 2),
231
+ and a muted duplicate is easy to leave muted (so never use one; one section
232
+ replaced is a take, see "Keeping the original").
233
+
234
+ **One lane per complete version.** Each lane holds the whole song, so one switch
235
+ plays a whole version and nothing is left silent. A lane with only a changed
236
+ section forces the unchanged sections into another lane, and playing one lane
237
+ alone then silences them.
238
+
239
+ 1. `set_track_lanes { track, fixedLanes: true }`: every item goes on lane 0
240
+ (version A). `laneCount` needs `fixedLanes: true`.
241
+ 2. With only lane 0 playing, run action 42505 ("Track lanes: Duplicate items from
242
+ playing lanes to new lanes"): lane 1 starts as a full copy.
243
+ 3. Make the change in lane 1. To bring a newly imported item in, `set_selected_items`
244
+ then 40068 (up one lane), 40107 (down one lane) or 42588 (bottom lane), and
245
+ delete the copy it replaces. Run `get_track_lanes` after each move.
246
+ 4. Name the lanes: `names: [{ lane: 0, name: "A original" }, { lane: 1, name: "B half-time chorus" }]`
247
+ (objects, not strings).
248
+ 5. **Switch:** `set_track_lanes { track, play: 1 }` plays lane 1 alone, `play: 0`
249
+ lane 0. A number is exclusive, an array (`play: [0, 2]`) is layered.
250
+ 6. **Decide:** `comp_lanes` takes sections from either lane onto a new comp lane
251
+ (a committed copy, not a switch). Delete the losers afterwards (action 42691
252
+ removes lanes that are not playing, with their items).
253
+
254
+ Gotchas:
255
+ - Unchanged sections exist in every lane, so an edit in one lane does not reach
256
+ the others. Finish shared edits first, or make them in each lane.
257
+ - `get_track_lanes` / `set_track_lanes` take `track`, not `trackIndex`.
258
+ - Turning lanes off puts every item on one lane, all playing (`undo_project`
259
+ restores).
260
+ - A full A/B is a lane choice plus a mix snapshot: lanes for notes and
261
+ arrangement, snapshots (`/mixer`) for faders, EQ and the master.
262
+ - For a few-note tweak, edit in place; lanes are for whole alternatives.
263
+
264
+ ## Workflow
265
+
266
+ 1. **Understand** the edit and the song structure (`list_regions`, `list_markers`,
267
+ `get_tempo_map`). Load `workflows/editing.md` for audio editing.
268
+ 2. **Protect:** `snapshot_save { name: "before-{task}" }` for the mix, and keep
269
+ the original items (rule 2).
270
+ 3. **Re-list**, then edit (rule 1), explaining the musical reason for each change.
271
+ 4. **Verify:** list the items and lanes again, play the changed range for the user
272
+ (`set_cursor_position` + `play`), and check the result with the meters through
273
+ `/mixer` when level or tone may have moved. Ask the user to listen: their ear
274
+ decides.
275
+ 5. **Report** what changed, where the originals are, and how to switch back.
276
+
277
+ ## Interpreting vague requests
278
+
279
+ "Slows down", "bigger", "less busy" can mean several things. State the reading you
280
+ chose (for "the groove slows down": half-time at the same tempo, not a tempo
281
+ change, since the other parts would have to follow) and offer the other.
@@ -0,0 +1,210 @@
1
+ ---
2
+ name: learn-plugin
3
+ description: Teach the mixing skills one plugin or a list of them (researched in parallel): researches each on the web, tests it live in REAPER and writes its plugin knowledge record to LoreKit, asking the user only what it couldn't work out
4
+ ---
5
+
6
+ # /learn-plugin
7
+
8
+ This skill teaches the mixing skills a plugin. It writes the plugin's **plugin
9
+ knowledge record** to the user's own LoreKit layer: scope `project::reaper-mcp`,
10
+ key `user::plugins::{vendor}/{plugin}`, following
11
+ `knowledge/reference/memory-protocol.md`.
12
+
13
+ It does the work itself before asking anything. The **`plugin-researcher`**
14
+ agent researches the plugin on the web, loads it on a scratch track, probes its
15
+ parameters, and writes the record. Then this skill asks the user **only** the
16
+ questions the agent couldn't answer, and folds the answers in.
17
+
18
+ If an opt-in extension drives the plugin (a `list_tool_categories` category named
19
+ after it, e.g. `vital`), the agent reads its internals through it and tags the record
20
+ `extension::<name>`, so `/mixer` and `/mastering` know to use it. A plugin that hides
21
+ its sound in internal state and has no extension gets a one-line offer to build one
22
+ (`reaper-mcp extension new <name>`, see `docs/EXTENSIONS.md`).
23
+
24
+ The mixing skills use the same agent to bootstrap plugins they don't know. To
25
+ recall or tidy memory, use `/mix-memory`. If the `memory.*` tools are not
26
+ connected, do not stop at an error: read `~/.claude/knowledge/reference/lorekit-setup.md` (in a clone: `knowledge/reference/lorekit-setup.md`) and walk
27
+ the user through connecting LoreKit (free, a few minutes), then carry on once it is.
28
+ If they decline, say there is nowhere to save the record and stop.
29
+
30
+ Every learned plugin should end up in the **built-in plugin list**
31
+ (`docs/PLUGINS.md`). A **publisher** (writing member of the `reaper-mcp` LoreKit
32
+ org, e.g. the maintainer) publishes the record and updates the list in their
33
+ clone (Step 5). Everyone else gets it there through a contribution PR, and the
34
+ list updates when the maintainer publishes it.
35
+
36
+ ## Trigger
37
+
38
+ The user types `/learn-plugin [plugin]`, or asks Claude to "learn about a
39
+ plugin", "research this plugin" or "add plugin knowledge".
40
+
41
+ ## Instructions
42
+
43
+ ### Step 1: Get the plugin name(s)
44
+
45
+ Take them from the arguments: one plugin, or a list (one per line, or comma
46
+ separated). If there are none, ask a single question:
47
+
48
+ > "Which plugin should I learn?"
49
+
50
+ If the user already said something about one (what they use it for, how they
51
+ set it up), keep it as caller context for that plugin in Step 2. Don't ask for
52
+ anything else yet.
53
+
54
+ Also check, once, whether the user is a **publisher**: `org.list`, and look for
55
+ the `reaper-mcp` org with a writing role (member, admin or owner). Remember the
56
+ answer for Steps 3 and 5. No `org.list` tool, or no such membership: not a
57
+ publisher.
58
+
59
+ ### Step 2: Dispatch the researchers, all at once
60
+
61
+ One `plugin-researcher` per plugin, **all in the same message** so they run in
62
+ parallel. Even when the user says "one at a time", run them in parallel: the
63
+ agents are built for it, and only the questions are asked plugin by plugin.
64
+ Give each one a short, unique uppercase tag for its scratch track:
65
+
66
+ ```text
67
+ Agent(subagent_type: "plugin-researcher",
68
+ prompt: "Plugin: <exact name>\nScratch track tag: <TAG, e.g. PROQ4>\nCaller context: <anything the user said, or 'none'>")
69
+ ```
70
+
71
+ Tell the user what is happening, in one line: each researcher looks the plugin
72
+ up on the web and briefly adds a scratch track `[MCP] plugin-research <TAG>` to
73
+ their project, which it removes afterwards. Several at once can make REAPER lag
74
+ for a moment while heavy plugins load. Then wait for the reports. As each one
75
+ arrives, give a one-line status (key, proposed preference, what was verified
76
+ live, number of open questions). Don't ask yet.
77
+
78
+ **No `plugin-researcher` agent available** (the Agent tool is missing, or the
79
+ agent isn't installed)? Do its steps here instead. Read
80
+ `~/.claude/agents/plugin-researcher.md` (in the repo:
81
+ `.claude/agents/plugin-researcher.md`) and follow it.
82
+
83
+ ### Step 3: Ask only the open questions
84
+
85
+ Show the report's summary lines: the key written, FX names, category/style,
86
+ what was verified live, sources.
87
+
88
+ Then ask **only** the report's open questions, all at once in one
89
+ `AskUserQuestion` call (up to 4). Each question offers the value the agent
90
+ already wrote as the first option, labelled "(keep)":
91
+
92
+ - **Preference:** offer the proposed number plus the neighbouring bands from
93
+ the field guide (e.g. "65 — good third-party (keep)", "80 — go-to",
94
+ "45 — fallback only").
95
+ - **Habit or settings questions:** offer "Use the researched defaults (keep)"
96
+ and let the user type their own in "Other".
97
+
98
+ More than 4 open questions? Ask the 4 that change the record the most. List the
99
+ rest as already filled in from research, and say the user can change them with
100
+ another `/learn-plugin`.
101
+
102
+ No open questions besides preference? Ask only the preference confirmation.
103
+
104
+ **Publishers only:** add one question per plugin, in the same call: "Publish
105
+ **[Plugin]** to built-in for every reaper-mcp user?" with "Publish (adds it to
106
+ the built-in plugin list)" first and "Keep it in my layer" second. It counts
107
+ toward the 4; with several plugins, one question "Publish all N to built-in?"
108
+ is enough.
109
+
110
+ **Several plugins:** start asking once most reports are in, without waiting for
111
+ a slow last one. `AskUserQuestion` takes 4 questions per call, so batch across
112
+ plugins and name the plugin in every question:
113
+
114
+ 1. Preferences first, 4 plugins per call. Two utilities with the same kind of
115
+ question can share one question.
116
+ 2. Then the facts about the user's setup that change the records the most,
117
+ e.g. what an offline instance or a hardware-control track is for.
118
+ 3. Then habits, settings and naming questions, which matter less.
119
+
120
+ Stop after about 3–4 calls. Anything still unasked keeps the researched value;
121
+ list those questions at the end, and say the user can change any of them with
122
+ another `/learn-plugin`. When an answer can be checked in REAPER (e.g. "it was
123
+ offline, check again"), check it read-only and fold in what you find.
124
+
125
+ ### Step 4: Fold the answers in
126
+
127
+ Answers that only kept the agent's values change nothing; skip the write.
128
+ Otherwise `memory.read` the `user::` key and change only what the user answered:
129
+
130
+ - preference → the header line **and** the `preference::<n>` tag
131
+ - when they pick it → `## When to prefer this`
132
+ - their own settings → a `###` use case under `## Recommended settings`,
133
+ marked as the user's own
134
+
135
+ Then `memory.write` the full record and full tag list (a write replaces both),
136
+ with `source_agent: "learn-plugin"` and no `ttl_days`. Keep everything else the
137
+ agent wrote, `## Learned notes` included.
138
+
139
+ **Several plugins:** make the writes in parallel, one subagent per record, or a
140
+ single subagent for several records that only change the preference. Give each
141
+ one the key, the exact changes, and the rule to keep everything else word for
142
+ word.
143
+
144
+ ### Step 5: Add it to the built-in plugin list
145
+
146
+ **Publisher who chose Publish:** run `/mix-memory publish` for each plugin's
147
+ `user::plugins::…` key (it merges with any built-in record, checks privacy,
148
+ writes the built-in key and removes the `user::` copy). Its last step rebuilds
149
+ `docs/PLUGINS.md` in the clone with `scripts/plugin-list.mjs`; with several
150
+ plugins, run the script once at the end. Say which rows were added and that
151
+ `docs/PLUGINS.md` needs a commit.
152
+
153
+ **Everyone else (or "Keep it in my layer"):** don't edit `docs/PLUGINS.md`; it
154
+ lists only built-in records, and a local edit blocks the bridge's one-click
155
+ Update. Tell the user, in two lines, how to get it listed:
156
+
157
+ > To share **[Plugin]** with every reaper-mcp user: open the bridge window's
158
+ > **Plugins** tab and press **Contribute**. That opens a pull request with your
159
+ > record; once the maintainer publishes it, it's added to the built-in plugin
160
+ > list (`docs/PLUGINS.md`).
161
+
162
+ ### Step 6: Confirm
163
+
164
+ > "Done! **[Plugin Name]** is saved to LoreKit as
165
+ > `user::plugins::{vendor}/{plugin}` (preference n/100, [category]).
166
+ > [Verified live: N params, the scaling of K of them. | Not tested live: reason.]
167
+ >
168
+ > The mixing skills will use it for **[category]** jobs when it's your
169
+ > highest-preference installed plugin, and will add to its learned notes as they
170
+ > work with it."
171
+
172
+ Published in Step 5? Say "is now built in as `plugins::{vendor}/{plugin}`"
173
+ instead, and add the `docs/PLUGINS.md` row to commit.
174
+
175
+ If the report said the scratch track couldn't be removed, say that first and
176
+ name the track.
177
+
178
+ **Several plugins:** one table instead (plugin, key, preference, category,
179
+ verified live, published or how to contribute), then the Step 7 overviews,
180
+ shortened to a few lines each.
181
+
182
+ ### Step 7: Show how it works
183
+
184
+ Always end with the overview from the report's **How it works** section, under
185
+ the heading **"How [Plugin Name] works"**. Update it with the user's answers
186
+ from Step 3 first: fill in or correct **Your setup**, and adjust **In practice**
187
+ where an answer changes what the mixer can do. Keep the agent's structure (what
188
+ it is, the key point, the control table, presets, your setup, in practice). Keep
189
+ it plain, not fancy.
190
+
191
+ The report has no overview (an older agent, or you did the steps inline)?
192
+ Write one in that structure from the final record.
193
+
194
+ ## Notes
195
+
196
+ - **Ask little.** Anything the web or REAPER can answer (exact FX name, vendor,
197
+ category, parameters, ranges, presets, typical settings) is never asked.
198
+ The user is asked about their taste and habits, or a fact the sources disagree
199
+ on and testing couldn't settle.
200
+ - **Self-improvement loop (per `memory-protocol.md`).** The main output is the
201
+ plugin record. If a run shows a recurring process lesson (e.g. a vendor whose
202
+ FX names don't match its marketing name, a category that's often mis-picked,
203
+ a plugin type whose params can't be probed), dedup-search and write or update
204
+ a `user::mixing-lessons::<slug>` lesson (`source_agent: "learn-plugin"`) and
205
+ mention it.
206
+ - The `fx::` tags must be the **exact** FX-browser names. They're matched as
207
+ case-insensitive substrings of installed FX names. The agent takes them from
208
+ `search_fx`, so they always match this machine.
209
+ - The header line and the tags must stay in step: lookups filter on the tags,
210
+ people read the header.
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: mastering
3
+ description: >
4
+ Masters the mix bus in a live REAPER session — gentle corrective EQ, glue
5
+ compression, and a true-peak limiter targeting a platform LUFS standard — while
6
+ verifying against metering and preserving the mix's character. Use when the user
7
+ asks to master, finalize, or prepare a track for Spotify/Apple/streaming or a
8
+ specific loudness target. Triggers on "master this", "prepare for Spotify",
9
+ "final master", "hit -14 LUFS", "/mastering".
10
+ argument-hint: '[platform or LUFS target]'
11
+ license: MIT
12
+ metadata:
13
+ author: mthines
14
+ version: '1.0.0'
15
+ workflow_type: applied
16
+ tags:
17
+ - mastering
18
+ - loudness
19
+ - lufs
20
+ - limiter
21
+ - reaper
22
+ - audio
23
+ ---
24
+
25
+ # Mastering
26
+
27
+ Act as a mastering engineer working the mix bus in a **live** REAPER session via
28
+ the `reaper` MCP tools. Apply a transparent chain that hits a loudness standard
29
+ while preserving the mix's character.
30
+
31
+ **Mastering is subtle** — moves are fractions of a dB. If large corrections are
32
+ needed, tell the user the mix needs work first and consider `/mixer`.
33
+
34
+ ## Targets
35
+
36
+ Default to **-14 LUFS, -1.0 dBTP** (safe for all streaming) unless the user names
37
+ a platform. Full target table: `reference/metering.md`.
38
+
39
+ ## Memory
40
+
41
+ Per `reference/memory-protocol.md` — plugin knowledge and lessons in LoreKit
42
+ (scope `project::reaper-mcp`), in two layers: the read-only **built-in** layer and
43
+ the user's own `user::` layer on top. Reads combine both; writes go to `user::` keys only.
44
+ - **Before:** read the `loop::mixing-lessons` bucket (capped at 5 + one search on
45
+ "mastering limiter loudness …") and, for your limiter/EQ/comp plugins, both
46
+ `get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }` and `memory.read`
47
+ of `user::plugins::{vendor}/{plugin}` — past
48
+ targets the user preferred and known gotchas (the user record wins).
49
+ - **Plugin gate — no plugin is touched before its memory is read.** Before the
50
+ first call that adds, sets, loads a preset for, writes MIDI to, or reads parameters
51
+ of a plugin (`add_fx`, `setup_fx_chain`, `set_fx_parameter`,
52
+ `set_multiple_fx_parameters`, `set_fx_preset`, `load_fx_chain`, MIDI for an
53
+ instrument track, take FX), look it up — every plugin, every time it is new to this
54
+ session, including ones the user named, ones already in the project and ones you
55
+ only meet while listing a chain. Never skip it because the plugin looks familiar.
56
+ Look up both layers: `list_builtin_knowledge { query: "<plugin name>" }` (or `tags:
57
+ ["fx::<FX name>"]`) / `get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }`,
58
+ and `memory.search` / `memory.read` of `user::plugins::{vendor}/{plugin}` (the user's
59
+ record wins). Then **follow the record**: its MIDI map and note ranges, parameter
60
+ scaling, recommended settings and gotchas decide what you do, and a setting you were
61
+ about to use that the record warns against is not used. Say it in one chat line
62
+ ("Recalled Odin x Ari Lite: notes <36 are keyswitches → transposing"). Keep a running
63
+ list of recalled plugins and don't re-read those. No record in either layer: say so
64
+ and carry on (or bootstrap it when the user asked for the plugin by name). LoreKit
65
+ not connected: say so once and use the built-in read only.
66
+ - **Unknown plugin?** Bootstrap it first (see protocol): dispatch the
67
+ `plugin-researcher` agent (or follow its steps yourself), then read its
68
+ `user::plugins::` record and use it.
69
+ - **At a correction point — write the lesson immediately, before your next
70
+ action** (the user found your master too loud and you backed off; a re-measure
71
+ missed the LUFS/true-peak target; you over-limited and lost crest). Non-
72
+ negotiable (see Hard Rules); **say in chat that you captured it** (key +
73
+ takeaway). A silent skip is a bug.
74
+ - **End-of-session retrospective (always, even on a clean master).** Before the
75
+ final report, ask: did the user override a target/ceiling, did a measurement
76
+ surprise me, did a lesson I had fail to fire? If anything surfaced, write or
77
+ UPDATE a lesson (rewriting the same key bumps the store's `seen_count`). A
78
+ lesson seen `>= 3×` is promotable to a Hard Rule via `/mix-memory promote`.
79
+ - **Durable facts:** also capture a verified limiter param map or a ceiling the
80
+ user kept under the `user::plugins::` record's `## Learned notes`
81
+ (read-merge-write; never write a built-in key). Name the key you wrote.
82
+
83
+ ## Workflow
84
+
85
+ 1. **Snapshot** — `snapshot_save { name: "pre-master" }`.
86
+ 2. **Discover plugins** — `list_available_fx`; prefer limiter Pro-L 2 > ReaLimit,
87
+ EQ Pro-Q 3 > ReaEQ (linear phase for mastering), comp Pro-C 2 > ReaComp. Check
88
+ the LoreKit plugin records (built-in + `user::`) for settings; bootstrap any
89
+ unknown plugin first.
90
+ 3. **Assess the bus** — `analyze_track_offline { trackIndex: -1, startTime: 0,
91
+ endTime: <song end>, sectionSeconds: 10 }`: integrated LUFS over the whole
92
+ song (not a few seconds of meter), LRA, true peak, crest, loudest/quietest
93
+ sections and band balance. With a reference song, add `referencePath` for the
94
+ loudness and tonal-balance delta. Peak should be -6 to -3 dBFS (reduce the
95
+ mix fader first if hotter); note distance from target LUFS and the dynamics.
96
+ Pass the target as `targetLufs` on every `read_track_lufs` / `measure_tracks`
97
+ call, so the bridge page shows each reading against it.
98
+ 4. **Corrective EQ** — gentle only. Typical: steep HPF 20–30 Hz; low shelf -0.5 to
99
+ -1 dB @ 80 Hz; low-mid dip -0.5 to -1 dB @ 250–350 Hz; +0.5 dB presence @
100
+ 2–4 kHz only if needed; air shelf +0.5 to +1 dB @ 10–12 kHz. The 2–5 kHz range
101
+ has outsized perceptual impact (`reference/perceived-loudness.md`). Judge the
102
+ bus spectrum on K-weighted `kDb`, never raw `db`, against a level-matched
103
+ reference band by band, and read it 3+ times (each read is a ~0.5 s snapshot). **If you're
104
+ EQing more than ±2 dB, the mix has a problem — go back.**
105
+ 5. **Glue compression** (optional) — only for cohesion: 1.5:1–2:1, slow attack
106
+ 30–80 ms, auto/200–500 ms release, **1–2 dB GR max**. More GR → fix the mix.
107
+ 6. **Limiter** (last in chain) — ceiling -1.0 dBTP (streaming) or -0.3 (CD); raise
108
+ input until integrated LUFS hits target; keep limiter GR under ~3 dB.
109
+ If the limiter pumps (guitars/bass dip on every drum hit), **clip before
110
+ it** rather than lowering drive or limiting harder. Put a clipper (e.g.
111
+ Free Clip 2) just before the limiter, with a ceiling ~1–1.5 dB under the
112
+ level that *arrives at it* (an upstream limiter's ceiling, not 0 dBFS).
113
+ The clipper only alters the peak samples, while the limiter's gain change
114
+ pulls the whole mix down for its release time. Seen live: master pumping
115
+ std 1.35 → 1.06 dB at +0.25 LU. Keep it to ≤1.5 dB (lesson
116
+ drum-bus-clip-buries-attack).
117
+ **Dynamics over loudness:** streaming turns everything down to about -14
118
+ LUFS, so a hotter master only loses punch there. Don't chase a loud
119
+ reference's LUFS. Offer louder as an option the user picks by ear.
120
+ 7. **Verify** — `analyze_track_offline` on the master over the whole song:
121
+ integrated LUFS within 0.5 of target, true peak below the ceiling, LRA and
122
+ crest genre-appropriate; `read_track_correlation` healthy (>0.3). To compare
123
+ chain versions, `analyze_track_aesthetics` on the same 30 s range keeps the
124
+ default level match (-18 LUFS), so the louder master does not win by level;
125
+ PQ moves under ~0.1 are noise (`reference/aesthetics-scoring.md`).
126
+ While the user is working in REAPER, verify during playback instead of
127
+ rendering (a render window takes focus). Use `measure_tracks` on the bus for
128
+ LUFS + true peak over the loud section, or the stock Loudness Meter in
129
+ true-peak mode. For a final choice, build 2–3 variants and switch them live
130
+ with `run_plan` (mixer skill, step 7). Render the deliverable once, when the
131
+ user asks.
132
+ 8. **Report** — first run the **end-of-session retrospective** (Memory) and write
133
+ any lesson it surfaces; then `snapshot_save { name: "master-v1" }` and report
134
+ target vs achieved LUFS, true peak, crest, the chain + settings, any
135
+ compromises, and **what you captured to memory (or that nothing was)**.
136
+
137
+ ## Hard Rules
138
+
139
+ <!-- Promotion target: recurring mastering lessons graduate here via /mix-memory promote. -->
140
+
141
+ - **No plugin without its memory.** Before the first add/set/preset/MIDI call on any plugin this session, look up its built-in and `user::` records and follow them (plugin gate under Memory). Skipping the lookup because the plugin looks familiar is a bug.
142
+
143
+ - **Capture the lesson at the correction point** — if the user overrides a
144
+ target/ceiling or a re-measure misses, write the lesson before your next action
145
+ and say you did. Never end a session that had a correction without a written
146
+ lesson. (Invariant.)
147
+ - **Mastering is the final stage** — the mix should already be finished.
148
+ - **If the bus clips before you start, reduce it first** — don't just add a limiter.
149
+ - **Linear-phase EQ if available** — avoids phase shift on the master.
150
+ - **Always A/B with `snapshot_restore`** — mastering is subtle enough to fool you.
151
+ - **A balanced master slopes gently down** from lows to highs on the analyzer.