@williamzujkowski/live-coding-music-mcp 3.0.0 → 4.0.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/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![CI](https://github.com/williamzujkowski/live-coding-music-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/williamzujkowski/live-coding-music-mcp/actions)
14
14
  [![npm version](https://img.shields.io/npm/v/@williamzujkowski/live-coding-music-mcp.svg)](https://www.npmjs.com/package/@williamzujkowski/live-coding-music-mcp)
15
15
  [![Nerq Trust](https://nerq.ai/badge/live-coding-music-mcp)](https://nerq.ai/kya/live-coding-music-mcp)
16
- [![Tools](https://img.shields.io/badge/tools-84-green.svg)]()
16
+ [![Tools](https://img.shields.io/badge/tools-26-green.svg)]()
17
17
  [![License](https://img.shields.io/badge/license-AGPL--3.0--or--later-blue.svg)](LICENSE)
18
18
 
19
19
  A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.cc/) from Claude for AI-assisted live-coding music, pattern generation, and algorithmic composition.
@@ -169,7 +169,7 @@ Common commands for immediate use:
169
169
  | Edit current pattern | `edit_pattern({ mode: "write", pattern: "..." })` |
170
170
  | Create an isolated session | `session({ action: "create", session_id: "live-1" })` |
171
171
 
172
- The legacy single-verb tools (`play`, `stop`, `save`, `undo`, `write`, `generate_pattern`, ...) still work in v3.0 as deprecated aliases. They forward to the consolidated tools and will be removed in v3.1 ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)).
172
+ The legacy single-verb tools (`play`, `stop`, `save`, `undo`, `write`, `generate_pattern`, ...) were deprecated aliases during the `3.0.x` line and were removed in v4.0.0 ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)). Use the consolidated tools above.
173
173
 
174
174
  **One-shot workflow:**
175
175
  ```
@@ -201,7 +201,7 @@ Then ask Claude:
201
201
 
202
202
  <!-- TOOLS:START -->
203
203
 
204
- **84 tools** across 15 categories:
204
+ **26 tools** across 14 categories:
205
205
 
206
206
  <details><summary><strong>Setup</strong> (1)</summary>
207
207
 
@@ -211,127 +211,94 @@ Then ask Claude:
211
211
 
212
212
  </details>
213
213
 
214
- <details><summary><strong>Pattern Editing</strong> (5)</summary>
214
+ <details><summary><strong>Pattern Editing</strong> (2)</summary>
215
215
 
216
216
  | Tool | Description |
217
217
  |------|-------------|
218
+ | `edit_pattern` | Mutate the current session pattern. |
218
219
  | `get_pattern` | Get current pattern code |
219
- | `write` | [DEPRECATED — use edit_pattern({ mode: "write" }) instead] Write pattern to editor with optional auto-play and validation |
220
- | `append` | [DEPRECATED — use edit_pattern({ mode: "append" }) instead] Append code to current pattern |
221
- | `insert` | [DEPRECATED — use edit_pattern({ mode: "insert" }) instead] Insert code at specific line |
222
- | `replace` | [DEPRECATED — use edit_pattern({ mode: "replace" }) instead] Replace pattern section |
223
220
 
224
221
  </details>
225
222
 
226
- <details><summary><strong>Playback</strong> (6)</summary>
223
+ <details><summary><strong>Playback</strong> (2)</summary>
227
224
 
228
225
  | Tool | Description |
229
226
  |------|-------------|
230
- | `status` | [DEPRECATED — use diagnostics({ level: "status" }) instead] Get current browser and playback status (quick state check) |
231
- | `clear` | [DEPRECATED — use edit_pattern({ mode: "clear" }) instead] Clear the editor |
232
- | `play` | [DEPRECATED — use playback({ action: "play" }) instead] Start playing pattern |
233
- | `pause` | [DEPRECATED — use playback({ action: "pause" }) instead] Pause playback |
234
- | `stop` | [DEPRECATED — use playback({ action: "stop" }) instead] Stop playback |
227
+ | `playback` | Control transport on the current session. |
235
228
  | `set_tempo` | Set BPM |
236
229
 
237
230
  </details>
238
231
 
239
- <details><summary><strong>Storage</strong> (3)</summary>
232
+ <details><summary><strong>Storage</strong> (1)</summary>
240
233
 
241
234
  | Tool | Description |
242
235
  |------|-------------|
243
- | `save` | [DEPRECATED — use pattern_store({ action: "save" }) instead] Save pattern with metadata |
244
- | `load` | [DEPRECATED — use pattern_store({ action: "load" }) instead] Load saved pattern |
245
- | `list` | [DEPRECATED — use pattern_store({ action: "list" }) instead] List saved patterns |
236
+ | `pattern_store` | Persist patterns to disk and read them back. |
246
237
 
247
238
  </details>
248
239
 
249
- <details><summary><strong>History</strong> (4)</summary>
240
+ <details><summary><strong>History</strong> (1)</summary>
250
241
 
251
242
  | Tool | Description |
252
243
  |------|-------------|
253
- | `undo` | [DEPRECATED — use history({ action: "undo" }) instead] Undo last action |
254
- | `redo` | [DEPRECATED — use history({ action: "redo" }) instead] Redo action |
255
- | `list_history` | [DEPRECATED — use history({ action: "list" }) instead] List recent pattern history with timestamps and previews |
256
- | `restore_history` | [DEPRECATED — use history({ action: "restore" }) instead] Restore a previous pattern from history by ID |
244
+ | `history` | Navigate or inspect the pattern edit history. |
257
245
 
258
246
  </details>
259
247
 
260
- <details><summary><strong>Generation</strong> (8)</summary>
248
+ <details><summary><strong>Generation</strong> (3)</summary>
261
249
 
262
250
  | Tool | Description |
263
251
  |------|-------------|
264
252
  | `compose` | Generate, write, and play a complete pattern in one step. Auto-initializes default browser if needed. |
265
- | `generate_pattern` | [DEPRECATED — use compose instead, which auto-inits and returns richer metadata] Generate complete pattern from style with optional auto-play. |
266
- | `generate_drums` | [DEPRECATED — use generate_part({ role: "drums" }) instead] Generate drum pattern |
267
- | `generate_bassline` | [DEPRECATED — use generate_part({ role: "bass" }) instead] Generate bassline |
268
- | `generate_melody` | [DEPRECATED — use generate_part({ role: "melody" }) instead] Generate melody from scale |
269
- | `generate_polyrhythm` | [DEPRECATED — use generate_rhythm({ type: "polyrhythm" }) instead] Generate polyrhythm |
270
- | `generate_fill` | [DEPRECATED — use generate_part({ role: "fill" }) instead] Generate drum fill |
271
- | `generate_variation` | [DEPRECATED — use transform({ op: "vary" }) instead] Create pattern variations (mis-named today; it transforms, not generates) |
253
+ | `generate_part` | Generate a single instrumental layer and append it to the current session pattern. |
254
+ | `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. |
272
255
 
273
256
  </details>
274
257
 
275
- <details><summary><strong>Music Theory</strong> (4)</summary>
258
+ <details><summary><strong>Music Theory</strong> (1)</summary>
276
259
 
277
260
  | Tool | Description |
278
261
  |------|-------------|
279
- | `generate_scale` | [DEPRECATED — use music_theory({ query: "scale" }) instead] Generate scale notes |
280
- | `generate_chord_progression` | [DEPRECATED — use music_theory({ query: "chord_progression" }) instead] Generate chord progression |
281
- | `generate_euclidean` | [DEPRECATED — use generate_rhythm({ type: "euclidean" }) instead] Generate Euclidean rhythm |
282
- | `apply_scale` | [DEPRECATED — use transform({ op: "scale" }) instead] Apply scale to notes |
262
+ | `music_theory` | Music-theory queries. |
283
263
 
284
264
  </details>
285
265
 
286
- <details><summary><strong>Transform</strong> (9)</summary>
266
+ <details><summary><strong>Transform</strong> (3)</summary>
287
267
 
288
268
  | Tool | Description |
289
269
  |------|-------------|
290
- | `transpose` | [DEPRECATED — use transform({ op: "transpose" }) instead] Transpose notes by semitones |
291
- | `reverse` | [DEPRECATED — use transform({ op: "reverse" }) instead] Reverse pattern |
292
- | `stretch` | [DEPRECATED — use transform({ op: "stretch" }) instead] Time stretch pattern |
293
- | `quantize` | [DEPRECATED — use transform({ op: "quantize" }) instead] Quantize to grid |
294
- | `humanize` | [DEPRECATED — use transform({ op: "humanize" }) instead] Add human timing variation |
295
- | `add_effect` | [DEPRECATED — use effect({ action: "add" }) instead] Add effect to pattern |
296
- | `remove_effect` | [DEPRECATED — use effect({ action: "remove" }) instead] Remove effect |
297
- | `add_swing` | [DEPRECATED — use transform({ op: "swing" }) instead] Add swing to pattern |
298
- | `set_energy` | [DEPRECATED — use shape({ dimension: "energy" }) instead] Adjust energy level 0-10. Auto-plays after applying. |
270
+ | `transform` | Apply a single transform op to the current session pattern. |
271
+ | `effect` | Add or remove a Strudel effect on the current session pattern. |
272
+ | `shape` | Shape the current pattern along one of three high-level dimensions. |
299
273
 
300
274
  </details>
301
275
 
302
- <details><summary><strong>AI</strong> (4)</summary>
276
+ <details><summary><strong>AI</strong> (1)</summary>
303
277
 
304
278
  | Tool | Description |
305
279
  |------|-------------|
306
- | `get_pattern_feedback` | [DEPRECATED — use ai_assist({ task: "feedback" }) instead] Get AI-powered creative feedback on the current pattern using Google Gemini. |
307
- | `jam_with` | [DEPRECATED — use ai_assist({ task: "jam" }) instead] AI generates a complementary layer to jam with your pattern. |
308
- | `shift_mood` | [DEPRECATED — use shape({ dimension: "mood" }) instead] Transform current pattern to match a different emotional mood. Moods: dark, euphoric, melancholic, aggressive, dreamy, peaceful, energetic. |
309
- | `refine` | [DEPRECATED — use shape({ dimension: "refine" }) instead] Incrementally refine current pattern: faster/slower/louder/quieter/brighter/darker/"more reverb"/drier. |
280
+ | `ai_assist` | Gemini-backed pattern assistance. |
310
281
 
311
282
  </details>
312
283
 
313
- <details><summary><strong>Analysis</strong> (7)</summary>
284
+ <details><summary><strong>Analysis</strong> (6)</summary>
314
285
 
315
286
  | Tool | Description |
316
287
  |------|-------------|
317
288
  | `analyze` | Audio analysis on the currently-playing pattern. |
318
- | `analyze_spectrum` | [DEPRECATED — use analyze({ include: ["spectrum"] }) instead] FFT spectrum analysis |
319
- | `analyze_rhythm` | [DEPRECATED — use analyze({ include: ["rhythm"] }) instead] Rhythm analysis |
320
- | `detect_tempo` | [DEPRECATED — use analyze({ include: ["tempo"] }) instead] BPM detection |
321
- | `detect_key` | [DEPRECATED — use analyze({ include: ["key"] }) instead] Key detection |
322
289
  | `validate_pattern_runtime` | Validate pattern with runtime error checking (monitors Strudel console for errors) |
323
- | `compare_patterns` | [DEPRECATED — use history({ action: "compare" }) instead] Compare two patterns from history showing differences |
290
+ | `validate_pattern_local` | Validate pattern syntax against the in-process StrudelEngine (no browser required) |
291
+ | `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
292
+ | `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
293
+ | `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
324
294
 
325
295
  </details>
326
296
 
327
- <details><summary><strong>Session</strong> (4)</summary>
297
+ <details><summary><strong>Session</strong> (1)</summary>
328
298
 
329
299
  | Tool | Description |
330
300
  |------|-------------|
331
- | `create_session` | [DEPRECATED — use session({ action: "create" }) instead] Create a new isolated Strudel browser session. |
332
- | `destroy_session` | [DEPRECATED — use session({ action: "destroy" }) instead] Close and destroy a Strudel session. |
333
- | `list_sessions` | [DEPRECATED — use session({ action: "list" }) instead] List all active Strudel sessions. |
334
- | `switch_session` | [DEPRECATED — use session({ action: "switch" }) instead] Change the default session. |
301
+ | `session` | Manage isolated Strudel browser sessions (multi-session, #108). |
335
302
 
336
303
  </details>
337
304
 
@@ -340,59 +307,27 @@ Then ask Claude:
340
307
  | Tool | Description |
341
308
  |------|-------------|
342
309
  | `export_midi` | Export current pattern to MIDI file. Parses note(), n(), and chord() functions. |
343
- | `screenshot` | [DEPRECATED — use browser_window({ action: "screenshot" }) instead] Take a screenshot of the current Strudel editor state |
310
+ | `browser_window` | Interact with the visible Strudel browser window. |
344
311
 
345
312
  </details>
346
313
 
347
- <details><summary><strong>Audio</strong> (3)</summary>
314
+ <details><summary><strong>Audio</strong> (1)</summary>
348
315
 
349
316
  | Tool | Description |
350
317
  |------|-------------|
351
- | `start_audio_capture` | [DEPRECATED — use audio_capture({ action: "start" }) instead] Start capturing audio. Audio must be playing. |
352
- | `stop_audio_capture` | [DEPRECATED — use audio_capture({ action: "stop" }) instead] Stop audio capture and return base64-encoded audio. |
353
- | `capture_audio_sample` | [DEPRECATED — use audio_capture({ action: "sample" }) instead] Capture a fixed-duration audio sample. |
318
+ | `audio_capture` | Record audio output from the live Strudel session. |
354
319
 
355
320
  </details>
356
321
 
357
- <details><summary><strong>Debug</strong> (5)</summary>
322
+ <details><summary><strong>Debug</strong> (1)</summary>
358
323
 
359
324
  | Tool | Description |
360
325
  |------|-------------|
361
- | `show_browser` | [DEPRECATED — use browser_window({ action: "show" }) instead] Bring browser window to foreground |
362
326
  | `diagnostics` | Inspect server and browser state. |
363
- | `show_errors` | [DEPRECATED — use diagnostics({ level: "errors" }) instead] Display captured console errors and warnings from Strudel |
364
- | `performance_report` | [DEPRECATED — use diagnostics({ level: "perf" }) instead] Get performance metrics and bottlenecks |
365
- | `memory_usage` | [DEPRECATED — use diagnostics({ level: "memory" }) instead] Get current memory usage statistics |
366
-
367
- </details>
368
-
369
- <details><summary><strong>Other</strong> (19)</summary>
370
-
371
- | Tool | Description |
372
- |------|-------------|
373
- | `ai_assist` | Gemini-backed pattern assistance. |
374
- | `suggest_pattern_from_audio` | [DEPRECATED — use ai_assist({ task: "suggest" }) instead] Analyze playing audio and suggest a complementary Strudel pattern. |
375
- | `validate_pattern_local` | Validate pattern syntax against the in-process StrudelEngine (no browser required) |
376
- | `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
377
- | `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
378
- | `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
379
- | `audio_capture` | Record audio output from the live Strudel session. |
380
- | `browser_window` | Interact with the visible Strudel browser window. |
381
- | `edit_pattern` | Mutate the current session pattern. |
382
- | `generate_part` | Generate a single instrumental layer and append it to the current session pattern. |
383
- | `music_theory` | Music-theory queries. |
384
- | `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. |
385
- | `history` | Navigate or inspect the pattern edit history. |
386
- | `playback` | Control transport on the current session. |
387
- | `session` | Manage isolated Strudel browser sessions (multi-session, #108). |
388
- | `pattern_store` | Persist patterns to disk and read them back. |
389
- | `transform` | Apply a single transform op to the current session pattern. |
390
- | `effect` | Add or remove a Strudel effect on the current session pattern. |
391
- | `shape` | Shape the current pattern along one of three high-level dimensions. |
392
327
 
393
328
  </details>
394
329
 
395
- _Auto-generated from source. 84 tools registered._
330
+ _Auto-generated from source. 26 tools registered._
396
331
 
397
332
  <!-- TOOLS:END -->
398
333
 
@@ -682,7 +617,7 @@ The Strudel MCP Server is built with a modular architecture that separates conce
682
617
  #### 1. **StrudelMCPServer** (`src/server/server.ts`, ~510 lines)
683
618
 
684
619
  Thin MCP dispatcher that:
685
- - Aggregates 84 tool definitions from the per-domain modules in `src/server/tools/` (84 = 26 consolidated tools + 58 deprecated aliases; -58 once #178 lands)
620
+ - Aggregates 26 tool definitions from the per-domain modules in `src/server/tools/`
686
621
  - Routes `tools/call` requests to the right module's `execute()`
687
622
  - Wraps every response in the discriminated result envelope (`{ ok, errorCategory, isRetryable, ... }`)
688
623
  - Tracks initialization, per-session history bundles, per-session audio capture services
@@ -1546,7 +1481,7 @@ npm run build
1546
1481
  # Check if server responds
1547
1482
  echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
1548
1483
 
1549
- # Should return JSON with 84 tools (post-v3.0; ~26 after #178 alias removal)
1484
+ # Should return JSON with 26 tools
1550
1485
 
1551
1486
  # Reinstall MCP server in Claude
1552
1487
  claude mcp remove strudel
@@ -1725,6 +1660,6 @@ Earlier versions of this package (including `@williamzujkowski/strudel-mcp-serve
1725
1660
 
1726
1661
  ---
1727
1662
 
1728
- **v3.0.0** — Open source, AGPL-3.0-or-later, experimental | [Report issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) | [Contribute](https://github.com/williamzujkowski/live-coding-music-mcp/pulls)
1663
+ **v4.0.0** — Open source, AGPL-3.0-or-later, experimental | [Report issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) | [Contribute](https://github.com/williamzujkowski/live-coding-music-mcp/pulls)
1729
1664
 
1730
1665
  *This project is under active development. Core features work, but expect bugs and breaking changes. Not recommended for production use.*
@@ -67,7 +67,7 @@ export class StrudelMCPServer {
67
67
  constructor() {
68
68
  this.server = new Server({
69
69
  name: 'live-coding-music-mcp',
70
- version: '3.0.0',
70
+ version: '4.0.0',
71
71
  }, {
72
72
  capabilities: {
73
73
  tools: {},
@@ -188,10 +188,10 @@ export class StrudelMCPServer {
188
188
  async getCurrentPatternSafe(sessionId) {
189
189
  if (sessionId) {
190
190
  // Explicit session — strict lookup, no pre-init stash. Named sessions
191
- // must be created via `create_session` before they're useful.
191
+ // must be created via `session({ action: "create" })` before they're useful.
192
192
  const sessionController = this.sessionManager.getSession(sessionId);
193
193
  if (!sessionController) {
194
- throw new Error(`Session '${sessionId}' not found. Create it first with create_session.`);
194
+ throw new Error(`Session '${sessionId}' not found. Create it first with session({ action: "create" }).`);
195
195
  }
196
196
  try {
197
197
  return await sessionController.getCurrentPattern();
@@ -216,7 +216,7 @@ export class StrudelMCPServer {
216
216
  if (sessionId) {
217
217
  const sessionController = this.sessionManager.getSession(sessionId);
218
218
  if (!sessionController) {
219
- throw new Error(`Session '${sessionId}' not found. Create it first with create_session.`);
219
+ throw new Error(`Session '${sessionId}' not found. Create it first with session({ action: "create" }).`);
220
220
  }
221
221
  return await sessionController.writePattern(pattern);
222
222
  }
@@ -240,7 +240,7 @@ export class StrudelMCPServer {
240
240
  if (sessionId) {
241
241
  const controller = this.sessionManager.getSession(sessionId);
242
242
  if (!controller) {
243
- throw new Error(`Session '${sessionId}' not found. Create it first with create_session.`);
243
+ throw new Error(`Session '${sessionId}' not found. Create it first with session({ action: "create" }).`);
244
244
  }
245
245
  return controller;
246
246
  }
@@ -274,7 +274,7 @@ export class StrudelMCPServer {
274
274
  // Save current state for undo and history (#41) before any edit
275
275
  // (#179): route to the session-specific bundle. Default session is
276
276
  // 'default'; named sessions get their own isolated stacks.
277
- if (['write', 'append', 'insert', 'replace', 'clear'].includes(name)) {
277
+ if (name === 'edit_pattern') {
278
278
  const sid = args?.session_id;
279
279
  const canRead = sid !== undefined || this.isInitialized;
280
280
  if (canRead) {
@@ -288,7 +288,7 @@ export class StrudelMCPServer {
288
288
  id: this.historyIdCounter,
289
289
  pattern: current,
290
290
  timestamp: new Date(),
291
- action: name,
291
+ action: args?.mode ?? 'write',
292
292
  });
293
293
  if (bundle.undoStack.length > this.MAX_HISTORY)
294
294
  bundle.undoStack.shift();
@@ -421,7 +421,7 @@ export class StrudelMCPServer {
421
421
  if (sessionId) {
422
422
  const sessionController = this.sessionManager.getSession(sessionId);
423
423
  if (!sessionController) {
424
- throw new Error(`Session '${sessionId}' not found. Create it first with create_session.`);
424
+ throw new Error(`Session '${sessionId}' not found. Create it first with session({ action: "create" }).`);
425
425
  }
426
426
  if (!sessionController.page) {
427
427
  throw new Error(`Session '${sessionId}' has no active page yet.`);
@@ -1,16 +1,12 @@
1
1
  /**
2
2
  * ai domain — AI-powered feedback, pattern suggestion, and jamming.
3
3
  *
4
- * Owns (3 tools): get_pattern_feedback, suggest_pattern_from_audio,
5
- * jam_with.
4
+ * Owns one consolidated tool (`ai_assist(task=feedback|suggest|jam)`) —
5
+ * all three tasks share Gemini's rate limiting and auth.
6
6
  *
7
- * Per the #110 audit, these collapse into a single `ai_assist(task=...)`
8
- * tool — they all share Gemini's rate limiting and auth, so the merge
9
- * is natural. Deferred until external contracts stabilize.
10
- *
11
- * `jam_with` carries six private helpers that analyze the current
7
+ * The `jam` task carries six private helpers that analyze the current
12
8
  * pattern (tempo/key/style detection, layer detection, merge logic)
13
- * and that are used only by this tool. They live here.
9
+ * and that are used only here. They live in this module.
14
10
  */
15
11
  import { Logger } from '../../utils/Logger.js';
16
12
  const logger = new Logger();
@@ -56,52 +52,6 @@ export const tools = [
56
52
  required: ['task'],
57
53
  },
58
54
  },
59
- {
60
- name: 'get_pattern_feedback',
61
- description: '[DEPRECATED — use ai_assist({ task: "feedback" }) instead] Get AI-powered creative feedback on the current pattern using Google Gemini.',
62
- inputSchema: {
63
- type: 'object',
64
- properties: {
65
- includeAudio: { type: 'boolean', description: 'Include audio analysis (plays pattern briefly). Default: false' },
66
- style: { type: 'string', description: 'Optional style hint for context (e.g., "techno", "ambient")' },
67
- ...SESSION_ID_PROP,
68
- },
69
- },
70
- },
71
- {
72
- name: 'suggest_pattern_from_audio',
73
- description: '[DEPRECATED — use ai_assist({ task: "suggest" }) instead] Analyze playing audio and suggest a complementary Strudel pattern.',
74
- inputSchema: {
75
- type: 'object',
76
- properties: {
77
- style: { type: 'string', description: 'Optional style hint (e.g., "ambient", "techno", "jazz")' },
78
- role: {
79
- type: 'string',
80
- enum: ['complement', 'bassline', 'melody', 'percussion'],
81
- description: 'What role the suggested pattern should fill. Default: complement',
82
- },
83
- ...SESSION_ID_PROP,
84
- },
85
- },
86
- },
87
- {
88
- name: 'jam_with',
89
- description: '[DEPRECATED — use ai_assist({ task: "jam" }) instead] AI generates a complementary layer to jam with your pattern.',
90
- inputSchema: {
91
- type: 'object',
92
- properties: {
93
- layer: {
94
- type: 'string',
95
- enum: ['drums', 'bass', 'melody', 'pad', 'texture'],
96
- description: 'Type of layer to add: drums, bass, melody, pad, or texture',
97
- },
98
- style_hint: { type: 'string', description: 'Optional style guidance (e.g., "funky", "minimal", "atmospheric")' },
99
- auto_play: { type: 'boolean', description: 'Start playback after adding layer (default: true)' },
100
- ...SESSION_ID_PROP,
101
- },
102
- required: ['layer'],
103
- },
104
- },
105
55
  ];
106
56
  export const toolNames = new Set(tools.map(t => t.name));
107
57
  export async function execute(name, args, ctx) {
@@ -117,12 +67,6 @@ export async function execute(name, args, ctx) {
117
67
  throw new Error(`Invalid task: ${t}. Must be one of: feedback, suggest, jam`);
118
68
  }
119
69
  }
120
- case 'get_pattern_feedback':
121
- return await getPatternFeedback(args?.includeAudio || false, args?.style, ctx, sid);
122
- case 'suggest_pattern_from_audio':
123
- return await suggestPatternFromAudio(args?.style, args?.role || 'complement', ctx, sid);
124
- case 'jam_with':
125
- return await jamWith(args.layer, args.style_hint, args.auto_play, ctx, sid);
126
70
  default:
127
71
  throw new Error(`ai module does not handle tool: ${name}`);
128
72
  }
@@ -307,7 +251,7 @@ Example patterns:
307
251
  style: style || 'auto',
308
252
  valid: validation.valid,
309
253
  validation_errors: validation.valid ? [] : validation.errors,
310
- usage: 'Use write tool to load this pattern, then play to hear it.',
254
+ usage: 'Use edit_pattern({ mode: "write" }) to load this pattern, then playback({ action: "play" }) to hear it.',
311
255
  };
312
256
  }
313
257
  catch (error) {
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * analysis domain — audio analysis + pattern validation (browser + local).
3
3
  *
4
- * Owns (10 tools):
5
- * browser-required: analyze, analyze_spectrum, analyze_rhythm,
6
- * detect_tempo, detect_key, validate_pattern_runtime
4
+ * Owns (6 tools):
5
+ * browser-required: analyze (include[] filter), validate_pattern_runtime
7
6
  * browser-free: validate_pattern_local, analyze_pattern_local,
8
7
  * query_pattern_events, transpile_pattern
9
8
  *
@@ -11,10 +10,6 @@
11
10
  * pairs naturally with validate_pattern_runtime (which monitors the
12
11
  * actual Strudel console). They were orphan handlers — implementations
13
12
  * present but not registered in tools/list — until #124.
14
- *
15
- * Post-consolidation (per #110 audit): a single `analyze` tool with
16
- * an `include[]` filter absorbs the 4 audio detection tools.
17
- * Local-engine tools stay distinct — different subsystem.
18
13
  */
19
14
  import { InputValidator } from '../../utils/InputValidator.js';
20
15
  const SESSION_ID_PROP = {
@@ -47,26 +42,6 @@ export const tools = [
47
42
  },
48
43
  },
49
44
  },
50
- {
51
- name: 'analyze_spectrum',
52
- description: '[DEPRECATED — use analyze({ include: ["spectrum"] }) instead] FFT spectrum analysis',
53
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
54
- },
55
- {
56
- name: 'analyze_rhythm',
57
- description: '[DEPRECATED — use analyze({ include: ["rhythm"] }) instead] Rhythm analysis',
58
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
59
- },
60
- {
61
- name: 'detect_tempo',
62
- description: '[DEPRECATED — use analyze({ include: ["tempo"] }) instead] BPM detection',
63
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
64
- },
65
- {
66
- name: 'detect_key',
67
- description: '[DEPRECATED — use analyze({ include: ["key"] }) instead] Key detection',
68
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
69
- },
70
45
  {
71
46
  name: 'validate_pattern_runtime',
72
47
  description: 'Validate pattern with runtime error checking (monitors Strudel console for errors)',
@@ -232,11 +207,6 @@ export async function execute(name, args, ctx) {
232
207
  switch (name) {
233
208
  case 'analyze':
234
209
  return await doAnalyze(args, controller);
235
- // Deprecated aliases — forward to consolidated handler.
236
- case 'analyze_spectrum': return await getSpectrum(controller);
237
- case 'analyze_rhythm': return await getRhythm(controller);
238
- case 'detect_tempo': return await getTempo(controller);
239
- case 'detect_key': return await getKey(controller);
240
210
  case 'validate_pattern_runtime': {
241
211
  InputValidator.validateStringLength(args.pattern, 'pattern', 10000, false);
242
212
  const validation = await controller.validatePatternRuntime(args.pattern, args.waitMs || 500);
@@ -1,12 +1,8 @@
1
1
  /**
2
2
  * capture domain — audio recording and MIDI export.
3
3
  *
4
- * Owns (4 tools): start_audio_capture, stop_audio_capture,
5
- * capture_audio_sample, export_midi.
6
- *
7
- * Per the #110 audit, the three audio_capture tools collapse into a
8
- * single `audio_capture(action=start|stop|sample)` post-split.
9
- * `export_midi` stays separate — MIDI is symbolic, audio is waveform.
4
+ * Owns two tools: `audio_capture(action=start|stop|sample)` and
5
+ * `export_midi` (kept separate — MIDI is symbolic, audio is waveform).
10
6
  *
11
7
  * The AudioCaptureService is lazy-instantiated module-side: we need
12
8
  * the current Playwright page for `injectRecorder()`, and that only
@@ -53,34 +49,6 @@ export const tools = [
53
49
  required: ['action'],
54
50
  },
55
51
  },
56
- {
57
- name: 'start_audio_capture',
58
- description: '[DEPRECATED — use audio_capture({ action: "start" }) instead] Start capturing audio. Audio must be playing.',
59
- inputSchema: {
60
- type: 'object',
61
- properties: {
62
- format: { type: 'string', enum: ['webm', 'opus'], description: 'Audio format (default: webm)' },
63
- maxDuration: { type: 'number', description: 'Maximum capture duration in milliseconds' },
64
- ...SESSION_ID_PROP,
65
- },
66
- },
67
- },
68
- {
69
- name: 'stop_audio_capture',
70
- description: '[DEPRECATED — use audio_capture({ action: "stop" }) instead] Stop audio capture and return base64-encoded audio.',
71
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
72
- },
73
- {
74
- name: 'capture_audio_sample',
75
- description: '[DEPRECATED — use audio_capture({ action: "sample" }) instead] Capture a fixed-duration audio sample.',
76
- inputSchema: {
77
- type: 'object',
78
- properties: {
79
- duration: { type: 'number', description: 'Duration in milliseconds (default: 5000)' },
80
- ...SESSION_ID_PROP,
81
- },
82
- },
83
- },
84
52
  {
85
53
  name: 'export_midi',
86
54
  description: 'Export current pattern to MIDI file. Parses note(), n(), and chord() functions.',
@@ -113,12 +81,6 @@ export async function execute(name, args, ctx) {
113
81
  throw new Error(`Invalid action: ${a}. Must be one of: start, stop, sample`);
114
82
  }
115
83
  }
116
- case 'start_audio_capture':
117
- return await startAudioCapture(args?.format, args?.maxDuration, ctx, sid);
118
- case 'stop_audio_capture':
119
- return await stopAudioCapture(ctx, sid);
120
- case 'capture_audio_sample':
121
- return await captureAudioSample(args?.duration, ctx, sid);
122
84
  case 'export_midi':
123
85
  return await exportMidi(args?.filename, args?.duration, args?.bpm, args?.format, ctx, sid);
124
86
  default:
@@ -134,7 +96,7 @@ async function startAudioCapture(format, _maxDuration, ctx, sid) {
134
96
  await service.startCapture(ctx.getController(sid).page, { format });
135
97
  return {
136
98
  success: true,
137
- message: 'Audio capture started. Use stop_audio_capture to get the recorded audio.',
99
+ message: 'Audio capture started. Use audio_capture({ action: "stop" }) to get the recorded audio.',
138
100
  format: format || 'webm',
139
101
  };
140
102
  }
@@ -1,14 +1,7 @@
1
1
  /**
2
2
  * compose domain — high-level UX tools that aren't a thin verb on a
3
- * subsystem: `compose` (one-shot generate+write+play) and `show_browser`
4
- * (bring the Strudel window forward).
5
- *
6
- * Post-consolidation (per #110 audit):
7
- * - `compose` absorbs `generate_pattern` after the alias period
8
- * - `show_browser` merges with `screenshot` into `browser_window`
9
- * These targets live in different epics (#120). Keeping the two tools
10
- * together here matches today's "UX Tools" grouping; the file is small
11
- * enough to split later without disruption.
3
+ * subsystem: `compose` (one-shot generate+write+play) and
4
+ * `browser_window` (show or screenshot the Strudel window).
12
5
  */
13
6
  import { InputValidator } from '../../utils/InputValidator.js';
14
7
  const SESSION_ID_PROP = {
@@ -35,11 +28,6 @@ export const tools = [
35
28
  required: ['action'],
36
29
  },
37
30
  },
38
- {
39
- name: 'show_browser',
40
- description: '[DEPRECATED — use browser_window({ action: "show" }) instead] Bring browser window to foreground',
41
- inputSchema: { type: 'object', properties: { ...SESSION_ID_PROP } },
42
- },
43
31
  {
44
32
  name: 'compose',
45
33
  description: 'Generate, write, and play a complete pattern in one step. Auto-initializes default browser if needed.',
@@ -101,8 +89,6 @@ export async function execute(name, args, ctx) {
101
89
  }
102
90
  return a === 'show' ? await doShow(ctx, sid) : await doScreenshot(args, ctx, sid);
103
91
  }
104
- case 'show_browser':
105
- return await doShow(ctx, sid);
106
92
  case 'compose': {
107
93
  InputValidator.validateStringLength(args.style, 'style', 100, false);
108
94
  if (args.key) {