@williamzujkowski/live-coding-music-mcp 3.0.0 → 4.1.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.
Files changed (53) hide show
  1. package/README.md +212 -780
  2. package/dist/AudioAnalyzer.js +1294 -91
  3. package/dist/PatternStore.js +276 -23
  4. package/dist/StrudelController.js +388 -56
  5. package/dist/server/resources.js +27 -20
  6. package/dist/server/server.js +391 -83
  7. package/dist/server/tools/ai.js +129 -152
  8. package/dist/server/tools/analysis.js +170 -91
  9. package/dist/server/tools/capture.js +128 -55
  10. package/dist/server/tools/compose.js +28 -42
  11. package/dist/server/tools/diagnostics.js +23 -53
  12. package/dist/server/tools/editor.js +63 -72
  13. package/dist/server/tools/generate.js +45 -167
  14. package/dist/server/tools/history.js +35 -66
  15. package/dist/server/tools/playback.js +7 -22
  16. package/dist/server/tools/session.js +41 -47
  17. package/dist/server/tools/storage.js +173 -50
  18. package/dist/server/tools/transform.js +136 -199
  19. package/dist/server/tools/types.js +209 -14
  20. package/dist/services/AudioCaptureService.js +302 -33
  21. package/dist/services/AudioExportService.js +318 -0
  22. package/dist/services/BrowserOnlyFunctions.js +149 -0
  23. package/dist/services/EventDensityProbe.js +324 -0
  24. package/dist/services/GeminiService.js +221 -36
  25. package/dist/services/IsolatedEngineRunner.js +308 -0
  26. package/dist/services/IsolatedStrudelEngine.js +135 -0
  27. package/dist/services/LocalPatternEngine.js +16 -0
  28. package/dist/services/MIDIExportService.js +765 -71
  29. package/dist/services/MIDIImportService.js +474 -0
  30. package/dist/services/MusicTheory.js +85 -13
  31. package/dist/services/PatternGenerator.js +168 -85
  32. package/dist/services/PatternSandbox.js +359 -0
  33. package/dist/services/SessionManager.js +338 -65
  34. package/dist/services/StrudelEngine.js +218 -12
  35. package/dist/services/StrudelEngineHelpers.js +24 -8
  36. package/dist/services/StyleRegistry.js +204 -0
  37. package/dist/services/Transferable.js +114 -0
  38. package/dist/services/ai/AiTransport.js +56 -0
  39. package/dist/services/ai/AudioMeasurements.js +155 -0
  40. package/dist/services/ai/CliTransport.js +256 -0
  41. package/dist/services/engineChild.js +83 -0
  42. package/dist/services/engineChildPath.js +28 -0
  43. package/dist/utils/CategorisedError.js +59 -0
  44. package/dist/utils/ErrorRecovery.js +130 -110
  45. package/dist/utils/InputValidator.js +55 -7
  46. package/dist/utils/PatternValidator.js +136 -17
  47. package/dist/utils/SafePath.js +112 -0
  48. package/dist/utils/ServerConfig.js +248 -0
  49. package/dist/utils/TableLookup.js +41 -0
  50. package/dist/utils/Tempo.js +143 -0
  51. package/package.json +17 -5
  52. package/dist/services/__mocks__/StrudelEngine.js +0 -157
  53. package/dist/types/index.js +0 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  >
5
5
  > **Unofficial fan project.** Not affiliated with, or endorsed by, the [Strudel project](https://codeberg.org/uzu/strudel). This adapter exists to make live-coding music accessible to beginners who want to try pattern-based music without learning the whole ecosystem first.
6
6
  >
7
- > **Status:** Beta | 86% statement coverage | Published to npm | Actively developed
7
+ > **Status:** Beta | 88% statement coverage | Published to npm | Actively developed
8
8
 
9
9
  <a href="https://glama.ai/mcp/servers/@williamzujkowski/live-coding-music-mcp">
10
10
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@williamzujkowski/live-coding-music-mcp/badge" alt="live-coding-music-mcp server" />
@@ -13,12 +13,12 @@
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-28-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.
20
20
 
21
- **Current State: Beta.** The core workflow (init → generate → write → play → analyze) works reliably with real audio output. 1771 tests pass, 86.76% statement coverage / 77.32% branch coverage. CI is hardened with OpenSSF Scorecard, SHA-pinned actions, CODEOWNERS, Dependabot, and lint as a blocking gate.
21
+ **Current State: Beta.** The core workflow (init → compose → playback → analyze) works reliably with real audio output. `npm test` reports ~3060 passing tests, <!-- COVERAGE:START -->88.99% statement coverage / 79.99% branch coverage<!-- COVERAGE:END -->. CI is hardened with OpenSSF Scorecard, SHA-pinned actions, CODEOWNERS, Dependabot, and lint as a blocking gate.
22
22
 
23
23
  **What "Beta" means here:**
24
24
  - Tool schemas are stable within minor versions; breaking changes require a major bump
@@ -30,8 +30,8 @@ A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.c
30
30
 
31
31
  - [Features](#features)
32
32
  - [Installation](#installation)
33
- - [Quick Reference](#quick-reference)
34
33
  - [Quick Start](#quick-start)
34
+ - [Quick Reference](#quick-reference)
35
35
  - [Available Tools](#available-tools)
36
36
  - [Usage Examples](#usage-examples)
37
37
  - [Architecture](#architecture)
@@ -44,39 +44,40 @@ A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.c
44
44
 
45
45
  ## Features
46
46
 
47
- ### 🎹 Music control
48
- - **84 MCP tools** covering pattern editing, playback, audio analysis, generation, history, sessions, and Gemini-backed assists. 26 are the canonical consolidated tools (`pattern_store`, `edit_pattern`, `transform`, `analyze`, `history`, `playback`, `effect`, `shape`, `audio_capture`, `browser_window`, `generate_part`, `generate_rhythm`, `music_theory`, `session`, `ai_assist`, ...); the rest are deprecated aliases kept for one release ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)).
47
+ ### Music control
48
+ - **28 MCP tools** covering pattern editing, playback, audio analysis, generation, history, sessions, MIDI import/export, and Gemini-backed assists. Each tool is enum-parameterized to keep the protocol surface small: `pattern_store({ action })`, `edit_pattern({ mode })`, `transform({ op })`, `analyze({ include })`, `history({ action })`, `playback({ action })`, `effect({ action })`, `shape({ dimension })`, `audio_capture({ action })`, `browser_window({ action })`, `generate_part({ role })`, `generate_rhythm({ type })`, `music_theory({ query })`, `session({ action })`, `ai_assist({ task })`, ... The 58 legacy single-verb aliases that forwarded to these were removed in v4.0.0 ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)).
49
49
  - **4 MCP resources** for catalog browsing without burning tool calls: `strudel://examples`, `strudel://patterns`, `strudel://styles`, `strudel://docs/tools`.
50
50
  - **Real browser automation** of Strudel.cc through Playwright.
51
51
  - **Multi-session support** — every browser-touching tool accepts an optional `session_id`; sessions have isolated browser pages, undo/redo/history stacks, and audio-capture services.
52
52
  - **Audio analysis** via Web Audio API (FFT spectrum, tempo detection, key detection, rhythm complexity).
53
53
  - **Template-based pattern generation** across 8 genres (techno, house, dnb, ambient, trap, jungle, jazz, experimental); optional Gemini-backed `ai_assist` for feedback, suggestions, and jamming.
54
- - **Music theory helpers**: 15+ scales, 8+ chord progression styles, euclidean and polyrhythm generation.
54
+ - **Music theory helpers**: 14 scales, 8 chord progression styles, euclidean and polyrhythm generation.
55
55
  - **Pattern persistence**: JSON-backed save/load with tags + the in-memory edit history (undo/redo/restore/compare).
56
56
  - **Result envelope** on every `tools/call`: clients branch on `{ ok, errorCategory, isRetryable }` instead of parsing free-text.
57
57
 
58
- ### 🔧 Testing & CI status
59
- - **1771 passing tests** across unit, integration, and example-validation suites.
60
- - **86.76% statement coverage / 77.32% branch coverage**.
61
- - **Lint blocking in CI**: 0 errors, ~163 warnings (mostly `any` in test mocks).
58
+ ### Testing & CI status
59
+ - **~3060 passing tests**: `npm test` runs ~3020 unit/integration/example tests in parallel, then 36 browser-validation tests serially against real Chromium. The coverage figure below is from the first tier, which is the one CI also runs — the browser tier adds ~0.2 points and CI does not execute it, so counting it would document coverage nothing verifies.
60
+ <!-- COVERAGE:START -->
61
+ - **88.99% statement coverage / 79.99% branch coverage** (90.5% functions, 89.75% lines), checked against `coverage/coverage-summary.json` by a drift guard.
62
+ <!-- COVERAGE:END -->
63
+ - **Lint blocking in CI**: 0 errors, ~195 warnings (mostly `any` in test mocks).
62
64
  - **OIDC trusted publishing** to npm with SLSA build provenance attestation on every release.
63
65
 
64
- **Not Production-Ready:** This is experimental software under active development. Use for exploration and experimentation. Expect breaking changes, bugs, and incomplete features. See [CONTRIBUTING.md](CONTRIBUTING.md) to help improve it.
66
+ **Not Production-Ready:** This is experimental software under active development. Use for exploration and experimentation. Expect breaking changes, bugs, and incomplete features. See [the Contributing section](#contributing) to help improve it.
65
67
 
66
- ### 🎼 Example patterns
68
+ ### Example patterns
67
69
 
68
- 18 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
70
+ 7 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
69
71
 
70
- - **Techno**: hard-techno, minimal-techno
71
- - **House**: deep-house, tech-house
72
- - **Drum & Bass**: liquid-dnb, neurofunk
73
- - **Ambient**: dark-ambient, drone
74
- - **Trap**: modern-trap, cloud-trap
75
- - **Jungle**: classic-jungle, ragga-jungle
76
- - **Jazz**: bebop, modal-jazz
77
- - **Longform** (multi-minute pieces): dark-ambient-journey, driving-techno, liquid-dnb-roller, nu-jazz-session
72
+ - **Ambient**: ambient-pad (70 BPM)
73
+ - **Dnb**: dnb-classic (174 BPM)
74
+ - **House**: house-classic (125 BPM)
75
+ - **Jazz**: jazz-ii-v-i (120 BPM)
76
+ - **Jungle**: amen-break (165 BPM)
77
+ - **Techno**: techno-driving (130 BPM)
78
+ - **Trap**: trap-modern (140 BPM)
78
79
 
79
- Each example is a JSON file with pattern code, BPM, key, and a description. See [`patterns/examples/README.md`](patterns/examples/README.md) for details. Agents can also list these via the `strudel://examples` MCP resource without making any tool calls.
80
+ Each example is a JSON file with pattern code, BPM, key, and a description, and each sets the tempo it declares (#367). See [`patterns/examples/README.md`](patterns/examples/README.md) for details. Agents can also list these via the `strudel://examples` MCP resource without making any tool calls.
80
81
 
81
82
  ## Migrating from `@williamzujkowski/strudel-mcp-server`
82
83
 
@@ -151,9 +152,86 @@ npx playwright install chromium
151
152
  npm run build
152
153
  ```
153
154
 
155
+ ## Quick Start
156
+
157
+ Get from install to your first generated pattern in under two minutes.
158
+
159
+ ### 1. Install
160
+
161
+ ```bash
162
+ npm install -g @williamzujkowski/live-coding-music-mcp
163
+ npx playwright install chromium # one-time
164
+ ```
165
+
166
+ Building from source instead? See [Installation → From Source](#from-source).
167
+
168
+ ### 2. Configure your MCP client
169
+
170
+ #### Claude Desktop
171
+
172
+ Edit your Claude Desktop config file:
173
+
174
+ | OS | Config path |
175
+ |---|---|
176
+ | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
177
+ | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
178
+ | Linux | `~/.config/Claude/claude_desktop_config.json` |
179
+
180
+ Add the server:
181
+
182
+ ```json
183
+ {
184
+ "mcpServers": {
185
+ "live-coding-music": {
186
+ "command": "live-coding-music-mcp"
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ Restart Claude Desktop. The server appears under the 🔌 plug icon.
193
+
194
+ #### Claude Code (CLI)
195
+
196
+ ```bash
197
+ # If installed globally
198
+ claude mcp add strudel live-coding-music-mcp
199
+
200
+ # If built from source
201
+ claude mcp add strudel node /path/to/live-coding-music-mcp/dist/index.js
202
+ ```
203
+
204
+ ### 3. Verify the server responds
205
+
206
+ ```bash
207
+ # From a global install
208
+ echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | live-coding-music-mcp
209
+
210
+ # From source
211
+ npm run validate
212
+ ```
213
+
214
+ You should see a JSON response listing **28 tools**. If you see fewer, the build is out of date — run `npm run build`.
215
+
216
+ ### 4. Make your first sound
217
+
218
+ In Claude, ask:
219
+
220
+ > Initialize Strudel and compose a techno beat.
221
+
222
+ **What you'll see:** A Chromium window opens (visibly — this is the live editor, not a hidden process) and lands on strudel.cc. Claude calls `init`, then `compose({ style: "techno" })`. A 4-on-the-floor pattern appears in the CodeMirror editor and starts playing through your speakers.
223
+
224
+ Prefer headless mode (no browser window)? Set `"headless": true` in `config.json` before the first `init` call — see [Configuration](#configuration). Note that tempo detection currently reflects how often the agent polls rather than the audio itself (#322), in headed or headless mode alike.
225
+
226
+ ### 5. Where to go next
227
+
228
+ - [Quick Reference](#quick-reference) below: tool cheat sheet for common operations.
229
+ - [Usage Examples](#usage-examples): multi-step workflows (composition, audio analysis, AI-assisted jamming).
230
+ - [`patterns/examples/`](patterns/examples/): 18 ready-to-play patterns across 7 genres plus 4 longform pieces. Agents can browse them via the `strudel://examples` MCP resource without burning tool calls.
231
+
154
232
  ## Quick Reference
155
233
 
156
- Common commands for immediate use:
234
+ Common operations as one-line tool calls:
157
235
 
158
236
  | Action | Tool call |
159
237
  |---|---|
@@ -169,39 +247,18 @@ Common commands for immediate use:
169
247
  | Edit current pattern | `edit_pattern({ mode: "write", pattern: "..." })` |
170
248
  | Create an isolated session | `session({ action: "create", session_id: "live-1" })` |
171
249
 
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)).
250
+ 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
251
 
174
252
  **One-shot workflow:**
175
253
  ```
176
- compose with style: "dnb", key: "Am", bpm: 174, auto_play: true
177
- ```
178
-
179
- ## Quick Start
180
-
181
- ### 1. Add to Claude
182
- ```bash
183
- # If installed globally
184
- claude mcp add strudel live-coding-music-mcp
185
-
186
- # If built from source
187
- claude mcp add strudel node /path/to/live-coding-music-mcp/dist/index.js
188
- ```
189
-
190
- ### 2. Start Using
191
- ```bash
192
- claude chat
254
+ compose with style: "dnb", key: "Am", tempo: 174, auto_play: true
193
255
  ```
194
256
 
195
- Then ask Claude:
196
- - "Initialize Strudel and create a techno beat"
197
- - "Generate a jazz chord progression in F major"
198
- - "Create a drum & bass pattern at 174 BPM"
199
-
200
257
  ## Available Tools
201
258
 
202
259
  <!-- TOOLS:START -->
203
260
 
204
- **84 tools** across 15 categories:
261
+ **28 tools** across 15 categories:
205
262
 
206
263
  <details><summary><strong>Setup</strong> (1)</summary>
207
264
 
@@ -211,127 +268,95 @@ Then ask Claude:
211
268
 
212
269
  </details>
213
270
 
214
- <details><summary><strong>Pattern Editing</strong> (5)</summary>
271
+ <details><summary><strong>Pattern Editing</strong> (2)</summary>
215
272
 
216
273
  | Tool | Description |
217
274
  |------|-------------|
275
+ | `edit_pattern` | Mutate the current session pattern. mode=write replaces the editor contents (default; mirrors the old write tool exactly, including optional pattern validation and auto_play). mode=append concatenates `code` after the current pattern with a newline. mode=insert places `code` at the given line `position`. mode=replace substitutes `search` with `replace` — the first occurrence only, unless replace_all is true. The response reports how many occurrences matched, were replaced, and remain. mode=clear empties the editor. Example: edit_pattern({ mode: "write", pattern: "s(\"bd\")", auto_play: true }). For reading the editor without mutating it use get_pattern; for the on-disk pattern catalog use pattern_store. |
218
276
  | `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
277
 
224
278
  </details>
225
279
 
226
- <details><summary><strong>Playback</strong> (6)</summary>
280
+ <details><summary><strong>Playback</strong> (2)</summary>
227
281
 
228
282
  | Tool | Description |
229
283
  |------|-------------|
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 |
235
- | `set_tempo` | Set BPM |
284
+ | `playback` | Control transport on the current session. action=play starts the editor pattern. action=pause halts the clock where it is, so play resumes mid-cycle. action=stop ends playback. Example: playback({ action: "play" }). For pattern editing use edit_pattern; for tempo use set_tempo. |
285
+ | `set_tempo` | Set BPM. Writes setcpm(bpm/4), assuming one bar of 4/4 per cycle. |
236
286
 
237
287
  </details>
238
288
 
239
- <details><summary><strong>Storage</strong> (3)</summary>
289
+ <details><summary><strong>Storage</strong> (2)</summary>
240
290
 
241
291
  | Tool | Description |
242
292
  |------|-------------|
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 |
293
+ | `pattern_store` | Persist patterns to disk and read them back. Use action=save to write the current session pattern under a name; action=load to restore a named pattern into the current session; action=list to enumerate the on-disk catalog (optionally filtered by tag). Example: pattern_store({ action: "save", name: "my-jam", tags: ["techno"] }). For session lifecycle (create/destroy/list active sessions) use the session tool — pattern_store deals with on-disk patterns, not runtime sessions. |
294
+ | `import_midi` | Convert a .mid file into a playable Strudel pattern (Phase 1: literal transcription, #201). Use source="base64" with data=<base64 string> for inline bytes, or source="path" with data=<basename> to read from the patterns/midi/ directory (path traversal blocked). Drum tracks (MIDI channel 10) emit one s() lane per sample so simultaneous kicks/hats do not collide. Pitched tracks emit note("...").s("piano") with simultaneous notes merged into [a,b,c] chord tokens. Phase 2+ (structural compression, voice separation, LLM idiomatic pass) tracked in separate issues. Example: import_midi({ source: "path", data: "drumloop.mid", steps_per_cycle: 16 }). For the reverse direction (Strudel → MIDI) use the export_midi tool. |
246
295
 
247
296
  </details>
248
297
 
249
- <details><summary><strong>History</strong> (4)</summary>
298
+ <details><summary><strong>History</strong> (1)</summary>
250
299
 
251
300
  | Tool | Description |
252
301
  |------|-------------|
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 |
302
+ | `history` | Navigate or inspect the pattern edit history. action=undo reverts the last edit on the targeted session. action=redo replays a previously-undone edit. action=list returns recent entries with timestamps and previews (limit defaults to 10). action=restore jumps the editor to a specific entry by id (current pattern goes on the undo stack). action=compare diffs two entries by id (or one entry vs current pattern). Example: history({ action: "list", limit: 5 }) — recent edits, newest first. For on-disk saved patterns use pattern_store — history deals with the in-memory edit timeline of the current session. |
257
303
 
258
304
  </details>
259
305
 
260
- <details><summary><strong>Generation</strong> (8)</summary>
306
+ <details><summary><strong>Generation</strong> (3)</summary>
261
307
 
262
308
  | Tool | Description |
263
309
  |------|-------------|
264
310
  | `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) |
311
+ | `generate_part` | Generate a single instrumental layer and append it to the current session pattern. role=drums takes `style` (e.g. "techno"/"house") and optional `complexity` 0-1. role=bass takes `key` (e.g. "C") + `style`. role=melody takes `root`/`scale` (e.g. C/minor) and optional `length` (notes). role=fill takes `style` and optional `bars`. Example: generate_part({ role: "drums", style: "techno", complexity: 0.7 }). For full compositions use compose; for rhythmic patterns use generate_rhythm; for music-theory queries use music_theory. |
312
+ | `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. type=euclidean produces a Euclidean rhythm with `hits` evenly distributed across `steps` (optional `sound` param, default "bd"). type=polyrhythm overlays multiple sound layers with given pattern numbers. Example: generate_rhythm({ type: "euclidean", hits: 3, steps: 8, sound: "hh" }). For complete patterns (drums/bass/melody) use generate_part; for whole compositions use compose. |
272
313
 
273
314
  </details>
274
315
 
275
- <details><summary><strong>Music Theory</strong> (4)</summary>
316
+ <details><summary><strong>Music Theory</strong> (1)</summary>
276
317
 
277
318
  | Tool | Description |
278
319
  |------|-------------|
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 |
320
+ | `music_theory` | Music-theory queries. query=scale returns the notes of a scale (e.g. "C major scale: C, D, E, F, G, A, B"). query=chord_progression returns a chord progression for the key/style AND writes the resulting chord pattern into the current session. Example: music_theory({ query: "scale", root: "C", scale: "major" }). For pattern generation (drums/bass/melody) use generate_part; for rhythmic patterns use generate_rhythm. |
283
321
 
284
322
  </details>
285
323
 
286
- <details><summary><strong>Transform</strong> (9)</summary>
324
+ <details><summary><strong>Transform</strong> (3)</summary>
287
325
 
288
326
  | Tool | Description |
289
327
  |------|-------------|
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. |
328
+ | `transform` | Apply a single transform op to the current session pattern. op=transpose shifts notes by `semitones`. op=reverse appends `.rev` to the pattern. op=stretch slows by `factor` (>1 slower, <1 faster). op=quantize snaps to the `grid` (e.g. "1/16"). op=humanize adds rand-nudge timing of `amount` (0-1). op=swing applies `.swing(amount)`. op=scale applies a `root`/`scale` filter to notes. op=vary returns a variation of `type` (subtle/moderate/extreme/glitch/evolving). Example: transform({ op: "transpose", semitones: 7 }). For effects (add/remove) use effect; for mood/energy/refine use shape; for tempo use set_tempo. |
329
+ | `effect` | Add or remove a Strudel effect on the current session pattern. action=add appends `.<effect>(<params>)`. action=remove strips EVERY `.<effect>(...)` call from the pattern, not just the last. Example: effect({ action: "add", effect: "lpf", params: "1000" }). For higher-level effect bundles (mood/energy/refine) use shape; for raw transforms use transform. |
330
+ | `shape` | Shape the current pattern along one of three high-level dimensions. dimension=mood applies a mood profile (dark/euphoric/melancholic/aggressive/dreamy/peaceful/energetic) with optional intensity 0-1. dimension=energy applies an energy level (integer 0-10). dimension=refine applies a directional refinement: faster/slower/louder/quieter/brighter/darker/"more reverb"/drier. All three auto-play by default. Example: shape({ dimension: "mood", target_mood: "dark", intensity: 0.8 }). For raw transform ops use transform; for explicit effects use effect. |
299
331
 
300
332
  </details>
301
333
 
302
- <details><summary><strong>AI</strong> (4)</summary>
334
+ <details><summary><strong>AI</strong> (1)</summary>
303
335
 
304
336
  | Tool | Description |
305
337
  |------|-------------|
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. |
338
+ | `ai_assist` | Gemini-backed pattern assistance. task=feedback returns creative critique on the current pattern (optionally with audio analysis). task=suggest analyzes the currently playing audio and suggests a complementary Strudel pattern as text (not auto-executed). task=jam generates a fresh layer (drums/bass/melody/pad/texture) and merges it into the current pattern, then auto-plays. All three share Gemini auth + rate limiting. Example: ai_assist({ task: "jam", layer: "bass" }). Needs GEMINI_API_KEY, or a logged-in claude/agy/codex CLI on PATH (#252). For non-AI pattern generation use generate_part; for full compositions use compose. |
310
339
 
311
340
  </details>
312
341
 
313
- <details><summary><strong>Analysis</strong> (7)</summary>
342
+ <details><summary><strong>Analysis</strong> (6)</summary>
314
343
 
315
344
  | Tool | Description |
316
345
  |------|-------------|
317
- | `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 |
346
+ | `analyze` | Audio analysis on the currently-playing pattern. include=["all"] (default) returns the full spectrum + features object, matching the pre-consolidation behaviour. include=["tempo"] returns only BPM with confidence. include=["key"] returns detected key + scale + confidence. include=["spectrum"] returns FFT features (bass, mid, treble, brightness, etc.). include=["rhythm"] returns rhythm-only analysis (complexity, density, syncopation). Combining values returns an object keyed by category, e.g. analyze({ include: ["tempo", "key"] }) → { tempo: {...}, key: {...} }. Example: analyze({ include: ["tempo"] }) to cheaply re-check BPM during a session. For static pattern analysis (no browser) use analyze_pattern_local; for runtime validation use validate_pattern_runtime. |
322
347
  | `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 |
348
+ | `validate_pattern_local` | Validate pattern syntax against the local StrudelEngine, which runs in a sandboxed child process (no browser required) |
349
+ | `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
350
+ | `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
351
+ | `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
324
352
 
325
353
  </details>
326
354
 
327
- <details><summary><strong>Session</strong> (4)</summary>
355
+ <details><summary><strong>Session</strong> (1)</summary>
328
356
 
329
357
  | Tool | Description |
330
358
  |------|-------------|
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. |
359
+ | `session` | Manage isolated Strudel browser sessions (multi-session, #108). action=create starts a new named session (sessions share one browser but isolated contexts). action=destroy closes a named session and releases its resources. action=list returns metadata for all active sessions (id, created, last_activity, is_playing, is_default). action=switch changes the default session that subsequent tool calls route to when no session_id is passed. Example: session({ action: "create", session_id: "live-set-1" }). For the on-disk pattern catalog use pattern_store(action=list) — session(action=list) lists *runtime* sessions, not saved patterns. |
335
360
 
336
361
  </details>
337
362
 
@@ -340,59 +365,35 @@ Then ask Claude:
340
365
  | Tool | Description |
341
366
  |------|-------------|
342
367
  | `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 |
368
+ | `browser_window` | Interact with the visible Strudel browser window. action=show brings the window to the foreground. action=screenshot captures the current editor view to disk (optional `filename`). Example: browser_window({ action: "screenshot", filename: "demo.png" }). For diagnostics (status/errors/perf) use diagnostics; for the editor itself use edit_pattern. |
344
369
 
345
370
  </details>
346
371
 
347
- <details><summary><strong>Audio</strong> (3)</summary>
372
+ <details><summary><strong>Audio</strong> (1)</summary>
348
373
 
349
374
  | Tool | Description |
350
375
  |------|-------------|
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. |
376
+ | `audio_capture` | Record audio output from the live Strudel session. action=start begins streaming capture (optional `format` webm/opus, default webm). action=stop ends the stream and returns base64-encoded audio. action=sample captures a fixed-`duration` window in one call (100-60000ms, default 5000ms). Example: audio_capture({ action: "sample", duration: 3000 }). Audio must be playing for capture to record meaningful data. For MIDI export use export_midi; for runtime diagnostics use diagnostics. Each session has its own recorder, so captures in different sessions do not interfere (#180). |
354
377
 
355
378
  </details>
356
379
 
357
- <details><summary><strong>Debug</strong> (5)</summary>
380
+ <details><summary><strong>Debug</strong> (1)</summary>
358
381
 
359
382
  | Tool | Description |
360
383
  |------|-------------|
361
- | `show_browser` | [DEPRECATED — use browser_window({ action: "show" }) instead] Bring browser window to foreground |
362
- | `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 |
384
+ | `diagnostics` | Inspect server and browser state. level=status returns a quick state snapshot (cache read, <15ms SLA), plus which config.json was read and any warnings from it. level=full returns detailed browser diagnostics including caches, errors, and performance. level=perf returns server-side timing metrics + top bottlenecks. level=memory returns process memory usage. level=errors returns captured console errors and warnings from Strudel. Default level=full preserves the pre-consolidation behaviour. Example: diagnostics({ level: "status" }) — millisecond-cheap. For screenshots use browser_window; for tool listings use the strudel://docs/tools resource. |
366
385
 
367
386
  </details>
368
387
 
369
- <details><summary><strong>Other</strong> (19)</summary>
388
+ <details><summary><strong>Other</strong> (1)</summary>
370
389
 
371
390
  | Tool | Description |
372
391
  |------|-------------|
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
+ | `export_audio` | Record a window of live Strudel audio and write it to a file. Returns a path plus what was actually recorded, not a wall of base64 — prefer this over audio_capture when you want the audio to exist somewhere. format=wav (default) decodes to 16-bit PCM a DAW will open; format=webm writes the raw Opus recording. Reports silent captures instead of writing a silent file and claiming success. Audio must already be playing: call playback({ action: "play" }) first. Example: export_audio({ duration: 4000, filename: "take-01" }). |
392
393
 
393
394
  </details>
394
395
 
395
- _Auto-generated from source. 84 tools registered._
396
+ _Auto-generated from source. 28 tools registered._
396
397
 
397
398
  <!-- TOOLS:END -->
398
399
 
@@ -409,7 +410,7 @@ Claude: [Initializes browser]
409
410
  [Starts playback]
410
411
 
411
412
  Pattern created:
412
- setcpm(130)
413
+ setcpm(130/4)
413
414
  stack(
414
415
  s("bd*4"),
415
416
  s("~ cp ~ cp"),
@@ -449,7 +450,7 @@ You: Generate a complete drum & bass track at 174 BPM
449
450
  Claude: [Creates multi-layer pattern with drums, bass, and pads]
450
451
 
451
452
  // dnb pattern in C at 174 BPM
452
- setcpm(174)
453
+ setcpm(174/4)
453
454
  stack(
454
455
  // Drums
455
456
  s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ cp ~ ~ cp ~ ~").fast(2),
@@ -504,7 +505,7 @@ You: Create an ambient soundscape with multiple layers
504
505
 
505
506
  Claude: [Generates complex multi-layer pattern]
506
507
 
507
- setcpm(90)
508
+ setcpm(90/4)
508
509
  stack(
509
510
  // Deep bass drone
510
511
  note("c1").s("sine").attack(4).release(8).gain(0.5),
@@ -600,7 +601,7 @@ note("c4 eb4 g4 bb4 c5").struct("1 1 1 1 1 1 1 1")
600
601
 
601
602
  ## Testing
602
603
 
603
- All tools have been tested with real Strudel.cc interaction:
604
+ Tools are exercised against real Strudel.cc interaction through the browser test suite; those are skipped in CI (require Playwright + audio) but run locally:
604
605
 
605
606
  ```bash
606
607
  # Run integration tests
@@ -620,273 +621,46 @@ node tests/strudel-integration.js
620
621
  "headless": false, // Set true for background operation
621
622
  "strudel_url": "https://strudel.cc/",
622
623
  "patterns_dir": "./patterns",
624
+ "exports_dir": "./exports",
625
+ "viewport": { "width": 1280, "height": 720 }, // or null to track the window size (#514)
626
+ "block_resources": ["image", "font", "media"], // resource types the page route aborts
623
627
  "audio_analysis": {
624
- "fft_size": 2048,
625
- "smoothing": 0.8
628
+ "fft_size": 2048, // power of 2 in [32, 32768]; code default is 1024
629
+ "smoothing": 0.8 // number in [0, 1]; default 0.8
626
630
  }
627
631
  }
628
632
  ```
629
633
 
630
- ## Architecture
631
-
632
- ### System Overview
633
-
634
- The Strudel MCP Server is built with a modular architecture that separates concerns and enables robust music generation:
635
-
636
- ```
637
- ┌─────────────────────────────────────────────────────────────┐
638
- │ Claude AI │
639
- │ (MCP Client) │
640
- └───────────────────────┬─────────────────────────────────────┘
641
- │ MCP Protocol (stdio)
642
- │
643
- ┌───────────────────────▼─────────────────────────────────────┐
644
- │ StrudelMCPServer │
645
- │ ┌────────────────────────────────────────────────────────┐ │
646
- │ │ Tool Request Handler │ │
647
- │ │ - Validates inputs │ │
648
- │ │ - Routes to appropriate service │ │
649
- │ │ - Handles errors gracefully │ │
650
- │ └────────────────────────────────────────────────────────┘ │
651
- └───────┬────────────┬────────────┬───────────┬──────────────┘
652
- │ │ │ │
653
- ┌────▼────┐ ┌───▼────┐ ┌───▼────┐ ┌──▼──────┐
654
- │ Strudel │ │ Music │ │Pattern │ │ Pattern │
655
- │Controller│ │ Theory │ │Generator│ │ Store │
656
- └────┬────┘ └────────┘ └────────┘ └─────────┘
657
- │
658
- ┌────▼────────────────────────────┐
659
- │ Playwright Browser │
660
- │ ┌──────────────────────────┐ │
661
- │ │ Strudel.cc Website │ │
662
- │ │ ┌────────────────────┐ │ │
663
- │ │ │ CodeMirror Editor │ │ │
664
- │ │ └────────────────────┘ │ │
665
- │ │ ┌────────────────────┐ │ │
666
- │ │ │ Audio Context │ │ │
667
- │ │ │ + Web Audio API │ │ │
668
- │ │ └────────┬───────────┘ │ │
669
- │ └───────────┼──────────────┘ │
670
- └──────────────┼──────────────────┘
671
- │
672
- ┌───────▼────────┐
673
- │ Audio Analyzer │
674
- │ - FFT Analysis│
675
- │ - Frequency │
676
- │ - Spectral │
677
- └────────────────┘
678
- ```
679
-
680
- ### Core Components
681
-
682
- #### 1. **StrudelMCPServer** (`src/server/server.ts`, ~510 lines)
683
-
684
- 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)
686
- - Routes `tools/call` requests to the right module's `execute()`
687
- - Wraps every response in the discriminated result envelope (`{ ok, errorCategory, isRetryable, ... }`)
688
- - Tracks initialization, per-session history bundles, per-session audio capture services
689
- - Advertises and serves MCP resources (`strudel://examples`, etc.)
690
- - Lazy-initializes the default browser controller on first browser-touching call
691
-
692
- Key Features:
693
- ```typescript
694
- - Pattern caching before browser init
695
- - Undo/redo stack management
696
- - Session history tracking
697
- - Generated pattern storage
698
- - Safe fallback mechanisms
699
- ```
700
-
701
- #### 2. **StrudelController** (`src/StrudelController.ts`)
702
-
703
- Browser automation layer using Playwright:
704
- - **Browser Management**: Chromium instance lifecycle
705
- - **Editor Control**: CodeMirror manipulation via DOM
706
- - **Playback Control**: Keyboard shortcuts for play/stop
707
- - **Performance Optimizations**:
708
- - Editor content caching (100ms TTL)
709
- - Direct CodeMirror API access
710
- - Resource blocking (images, fonts)
711
- - Fast DOM content loading
712
-
713
- ```typescript
714
- // Example: Optimized pattern writing
715
- async writePattern(pattern: string) {
716
- await this.page.evaluate((newPattern) => {
717
- const editor = document.querySelector('.cm-content');
718
- const view = editor.__view;
719
- view.dispatch({
720
- changes: { from: 0, to: view.state.doc.length, insert: newPattern }
721
- });
722
- }, pattern);
723
- }
724
- ```
725
-
726
- #### 3. **AudioAnalyzer** (`src/AudioAnalyzer.ts`)
727
-
728
- Real-time audio analysis via Web Audio API injection:
729
- - **FFT Analysis**: 1024-point FFT for spectral data
730
- - **Frequency Bands**: Bass, low-mid, mid, high-mid, treble
731
- - **Analysis Caching**: 50ms TTL for performance
732
- - **Features Extracted**:
733
- - Average amplitude
734
- - Peak frequency
735
- - Spectral centroid
736
- - Playing state detection
737
- - Frequency distribution
738
-
739
- ```typescript
740
- Features provided:
741
- - average: Overall amplitude (0-255)
742
- - peak: Maximum amplitude
743
- - peakFrequency: Dominant frequency in Hz
744
- - bass/mid/treble: Band-specific amplitudes
745
- - brightness: Timbral classification
746
- - isPlaying: Boolean playback state
747
- ```
748
-
749
- #### 4. **MusicTheory** (`src/services/MusicTheory.ts`)
750
-
751
- Music theory engine providing:
752
- - **15+ Scales**: Major, minor, modes, pentatonic, blues, whole-tone
753
- - **Chord Progressions**: Pop, jazz, blues, rock, folk, EDM
754
- - **Euclidean Rhythms**: Mathematical rhythm generation
755
- - **Arpeggio Generation**: Multiple patterns (up, down, random)
756
- - **Note Transposition**: Semitone-based pitch shifting
757
-
758
- Supported scales:
759
- ```typescript
760
- major, minor, dorian, phrygian, lydian, mixolydian,
761
- aeolian, locrian, pentatonic, blues, chromatic,
762
- wholetone, harmonic_minor, melodic_minor
763
- ```
764
-
765
- #### 5. **PatternGenerator** (`src/services/PatternGenerator.ts`)
634
+ `strudel_url` is the REPL the browser is pointed at — set it to run against a self-hosted or
635
+ pinned Strudel build. Only `http`/`https` are accepted; anything else falls back to the default
636
+ with a logged warning. `patterns_dir` is where `pattern_store` reads and writes.
766
637
 
767
- AI-powered pattern creation:
768
- - **Genre Templates**: Techno, house, DnB, trap, ambient, jazz, intelligent_dnb, trip_hop, boom_bap
769
- - **Drum Patterns**: 4 complexity levels per genre
770
- - **Basslines**: 8 different styles
771
- - **Melody Generation**: Scale-based with musical intervals
772
- - **Variations**: Subtle, moderate, extreme, glitch, evolving
773
- - **Fills**: 1-4 bar drum fills
638
+ `viewport` pins the Playwright page layout. Set it to `null` in a headed window so dragging the
639
+ window resizes the page and strudel's canvases follow (#514). `block_resources` lists the
640
+ resource types the page route aborts to speed up load; the default blocks `image`, `font`, and
641
+ `media`, which suits headless CI but degrades the live editor (fallback-font button metrics,
642
+ canvases that ignore window resizes). A live-coding setup wants `"block_resources": ["media"]`.
643
+ Both keys fall back to the defaults with a logged warning when invalid.
774
644
 
775
- Example generation:
776
- ```typescript
777
- generateCompletePattern('techno', 'C', 130)
778
- → Multi-layer pattern with drums, bass, chords, melody
779
- ```
780
-
781
- #### 6. **PatternStore** (`src/PatternStore.ts`)
782
-
783
- Persistent pattern storage:
784
- - **JSON-based**: Simple file storage
785
- - **Metadata**: Name, tags, timestamp, audio features
786
- - **Tag Filtering**: Organize by genre, mood, project
787
- - **Sorted Retrieval**: Most recent first
788
-
789
- ### Directory Structure
790
-
791
- ```
792
- live-coding-music-mcp/
793
- ├── src/
794
- │ ├── server/
795
- │ │ ├── server.ts # MCP dispatcher (~510 lines)
796
- │ │ ├── resources.ts # MCP resources (#131)
797
- │ │ └── tools/
798
- │ │ ├── ai.ts, analysis.ts, capture.ts, compose.ts,
799
- │ │ ├── diagnostics.ts, editor.ts, generate.ts, history.ts,
800
- │ │ ├── playback.ts, session.ts, storage.ts, transform.ts,
801
- │ │ └── types.ts # ToolContext, Envelope, helpers
802
- │ ├── services/
803
- │ │ ├── MusicTheory.ts # Scale/chord/euclidean helpers
804
- │ │ ├── PatternGenerator.ts # Template-based generation
805
- │ │ ├── SessionManager.ts # Multi-session lifecycle (#108)
806
- │ │ ├── AudioCaptureService.ts # Audio recording
807
- │ │ ├── MIDIExportService.ts # MIDI export
808
- │ │ ├── GeminiService.ts # Gemini API client (ai_assist)
809
- │ │ ├── StrudelEngine.ts # @strudel/* wrapper
810
- │ │ └── StrudelEngineHelpers.ts # Pure helpers (#107)
811
- │ ├── utils/
812
- │ │ ├── Logger.ts
813
- │ │ ├── PatternValidator.ts # Syntax + safety checks
814
- │ │ ├── ErrorRecovery.ts # Retry / backoff
815
- │ │ ├── PerformanceMonitor.ts
816
- │ │ └── InputValidator.ts # Input bound checks
817
- │ ├── StrudelController.ts # Browser automation (~800 lines)
818
- │ ├── AudioAnalyzer.ts # Audio analysis (~800 lines)
819
- │ ├── PatternStore.ts # On-disk pattern persistence
820
- │ └── index.ts # Entry point
821
- ├── src/__tests__/ # Jest suites (unit + integration + browser)
822
- ├── patterns/
823
- │ ├── examples/ # 18 bundled example patterns
824
- │ └── *.json # Saved patterns at runtime
825
- ├── scripts/
826
- │ ├── generate-tool-docs.ts # README tool-table generator
827
- │ └── generate-changelog.ts
828
- ├── config.json # Local config (gitignored)
829
- ├── package.json
830
- └── tsconfig.json
831
- ```
832
-
833
- ### Data Flow
834
-
835
- 1. **Tool Invocation**
836
- ```
837
- Claude → MCP Protocol → StrudelMCPServer
838
- ```
839
-
840
- 2. **Pattern Generation** (without browser)
841
- ```
842
- Server → PatternGenerator → MusicTheory → Pattern String
843
- ```
645
+ `exports_dir` is where `export_midi({format:"file"})` writes. Exported filenames are reduced to a
646
+ basename and confined to this directory — a name containing path separators is sanitized rather
647
+ than honoured, and the response reports the path actually written.
844
648
 
845
- 3. **Pattern Execution** (with browser)
846
- ```
847
- Server → StrudelController → Playwright → Strudel.cc
848
- ```
649
+ Unknown top-level keys are logged as warnings at startup rather than silently ignored.
849
650
 
850
- 4. **Audio Analysis**
851
- ```
852
- Strudel.cc → Web Audio API → AudioAnalyzer → Feature Data
853
- ```
854
-
855
- ### Performance Characteristics
856
-
857
- | Operation | Latency | Notes |
858
- |-----------|---------|-------|
859
- | Pattern Generation | <100ms | Pure computation |
860
- | Browser Init | ~3s | One-time cost |
861
- | Pattern Write | ~50ms | With caching |
862
- | Play/Stop | ~100ms | Keyboard shortcuts |
863
- | Audio Analysis | ~20ms | With 50ms cache |
864
- | Pattern Save | ~10ms | File I/O |
865
-
866
- ### Optimization Strategies
867
-
868
- 1. **Caching**
869
- - Editor content: 100ms TTL
870
- - Audio analysis: 50ms TTL
871
- - Generated patterns: Until browser init
651
+ `audio_analysis.fft_size` tunes the FFT bin count on the `AnalyserNode` attached to Strudel's audio graph — larger = better frequency resolution at higher CPU cost. `smoothing` is the analyser's `smoothingTimeConstant` (higher = steadier spectrum, more lag). Invalid values fall back to defaults with a warning; the frequency-band boundaries inside `analyze` rescale automatically so band Hz coverage stays consistent across FFT sizes.
872
652
 
873
- 2. **Resource Blocking**
874
- - Images, fonts, media blocked
875
- - Only load essential JavaScript/CSS
653
+ ## Architecture
876
654
 
877
- 3. **Direct API Access**
878
- - CodeMirror view manipulation
879
- - Keyboard shortcuts over button clicks
655
+ The server is a thin MCP dispatcher (`src/server/server.ts`, ~520 lines) over twelve per-domain tool modules (`src/server/tools/*.ts`), ten services (MusicTheory, PatternGenerator, SessionManager, AudioCaptureService, AudioExportService, GeminiService, MIDIExportService, MIDIImportService, StrudelEngine, PatternSandbox) plus a provider-agnostic AI transport layer (`src/services/ai/`), two controllers (StrudelController for Playwright, AudioAnalyzer for Web Audio API), and a JSON-on-disk PatternStore. Browser automation drives the editor on strudel.cc through `window.strudelMirror.editor.dispatch(...)` rather than keyboard simulation — about 80% faster.
880
656
 
881
- 4. **Lazy Loading**
882
- - Browser starts only when needed
883
- - Services initialized on-demand
657
+ For the full breakdown — component diagram, per-component responsibilities, directory layout, data flow, and optimization strategies — see **[ARCHITECTURE.md](ARCHITECTURE.md)**.
884
658
 
885
659
  ## Pattern Examples
886
660
 
887
661
  ### Minimal Techno (Verified Working)
888
662
  ```javascript
889
- setcpm(130)
663
+ setcpm(130/4)
890
664
  stack(
891
665
  s("bd*4").gain(0.9),
892
666
  s("~ cp ~ cp").room(0.2),
@@ -897,7 +671,7 @@ stack(
897
671
 
898
672
  ### Drum & Bass (Verified Working)
899
673
  ```javascript
900
- setcpm(174)
674
+ setcpm(174/4)
901
675
  stack(
902
676
  s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ sn:3 ~ ~ sn:3 ~ ~").fast(2),
903
677
  s("hh*16").gain(0.5),
@@ -929,347 +703,15 @@ docker-compose up
929
703
 
930
704
  ## Development
931
705
 
932
- ### Setup Development Environment
933
-
934
- ```bash
935
- # Clone the repository
936
- git clone https://github.com/williamzujkowski/live-coding-music-mcp.git
937
- cd live-coding-music-mcp
938
-
939
- # Install dependencies
940
- npm install
941
-
942
- # Install Playwright browsers
943
- npx playwright install chromium
944
-
945
- # Build the project
946
- npm run build
947
- ```
948
-
949
- ### Available Scripts
706
+ For development setup, scripts, debugging, adding new tools, and the release process, see **[DEVELOPMENT.md](DEVELOPMENT.md)**.
950
707
 
951
- ```bash
952
- # Development mode with hot reload
953
- npm run dev
954
-
955
- # Build TypeScript to dist/
956
- npm run build
957
-
958
- # Start production server
959
- npm start
960
-
961
- # Run all tests
962
- npm test
963
-
964
- # Run integration tests with real browser
965
- npm run test:integration
966
-
967
- # Run browser-specific tests
968
- npm run test:browser
969
-
970
- # Validate MCP protocol compliance
971
- npm run validate
972
-
973
- # Lint code
974
- npm run lint
975
-
976
- # Format code
977
- npm run format
978
-
979
- # Clean build artifacts
980
- npm clean
981
- ```
982
-
983
- ### Publishing to npm
984
-
985
- See [NPM_PUBLISHING.md](NPM_PUBLISHING.md) for complete publishing instructions.
986
-
987
- **Quick publish via GitHub Release:**
988
- ```bash
989
- npm version patch # or minor, major
990
- git push && git push --tags
991
- gh release create v$(node -p "require('./package.json').version") --generate-notes
992
- ```
993
-
994
- The package uses OIDC trusted publishing with provenance attestation for supply chain security.
995
-
996
- ### Adding new tools
997
-
998
- Tools live in per-domain modules under `src/server/tools/<domain>.ts`. `server.ts` just dispatches. To add a tool:
999
-
1000
- 1. **Pick the right domain module** (or add a new one). Add the tool definition to that module's `tools` array:
1001
-
1002
- ```typescript
1003
- export const tools: Tool[] = [
1004
- // ...
1005
- {
1006
- name: 'my_new_tool',
1007
- description: 'One-line description; agents read this to pick between adjacent tools',
1008
- inputSchema: {
1009
- type: 'object',
1010
- properties: {
1011
- param1: { type: 'string', description: 'What it is' },
1012
- session_id: { type: 'string', description: 'Optional session ID (#108)' },
1013
- },
1014
- required: ['param1'],
1015
- },
1016
- },
1017
- ];
1018
- ```
1019
-
1020
- 2. **Add the case** to the module's `execute()` switch:
1021
-
1022
- ```typescript
1023
- case 'my_new_tool':
1024
- return await ctx.getController(args.session_id).doSomething(args.param1);
1025
- ```
1026
-
1027
- 3. **Add a service method** if needed (`MusicTheory`, `PatternGenerator`, etc.) and surface it through `ToolContext` (`src/server/tools/types.ts`) if other modules need it.
1028
-
1029
- 4. **Don't hand-edit the README tool table.** It auto-generates via `npm run build` → `scripts/generate-tool-docs.ts`. A Jest test plus a CI step guard against drift.
1030
-
1031
- 5. **Use the envelope helpers** for returns: `ok(data)`, `empty(data)`, `err('validation', 'message')` from `src/server/tools/types.ts`. Raw returns still work — the dispatcher normalises them — but native envelope construction is clearer.
1032
-
1033
- 6. **Build and test**:
1034
-
1035
- ```bash
1036
- npm run build
1037
- echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my_new_tool","arguments":{"param1":"test"}},"id":2}' | node dist/index.js
1038
- ```
1039
-
1040
- ### Testing Strategy
1041
-
1042
- #### 1. Unit Tests
1043
- ```bash
1044
- # Run with Jest
1045
- npm test
1046
-
1047
- # Watch mode
1048
- npm run test:watch
1049
- ```
1050
-
1051
- #### 2. Integration Tests
1052
- ```bash
1053
- # Full integration with real browser
1054
- npm run test:integration
1055
-
1056
- # This tests:
1057
- # - Browser initialization
1058
- # - Pattern generation
1059
- # - Audio analysis
1060
- # - Pattern storage
1061
- # - All 84 registered tools
1062
- ```
1063
-
1064
- #### 3. Manual Testing
1065
- ```bash
1066
- # Development mode
1067
- npm run dev
1068
-
1069
- # In another terminal
1070
- claude mcp add strudel-dev node $(pwd)/dist/index.js
1071
- claude chat
1072
-
1073
- # Then interact with Claude
1074
- ```
1075
-
1076
- ### Code Quality
1077
-
1078
- **TypeScript Configuration**
1079
- ```json
1080
- // tsconfig.json
1081
- {
1082
- "compilerOptions": {
1083
- "strict": true, // Strict type checking
1084
- "esModuleInterop": true, // Better module compatibility
1085
- "target": "ES2020", // Modern JavaScript
1086
- "module": "ES2020", // ES modules
1087
- "moduleResolution": "node"
1088
- }
1089
- }
1090
- ```
1091
-
1092
- **Linting & Formatting**
1093
- ```bash
1094
- # ESLint
1095
- npm run lint
1096
-
1097
- # Prettier
1098
- npm run format
1099
-
1100
- # Pre-commit hooks recommended
1101
- ```
1102
-
1103
- ### Debugging
1104
-
1105
- **Enable Debug Logging**
1106
- ```bash
1107
- # Set DEBUG environment variable
1108
- DEBUG=strudel:* npm start
1109
-
1110
- # Or specific modules
1111
- DEBUG=strudel:controller npm start
1112
- DEBUG=strudel:audio npm start
1113
- ```
1114
-
1115
- **VS Code Launch Configuration**
1116
- ```json
1117
- {
1118
- "type": "node",
1119
- "request": "launch",
1120
- "name": "Debug MCP Server",
1121
- "program": "${workspaceFolder}/dist/index.js",
1122
- "preLaunchTask": "npm: build",
1123
- "console": "integratedTerminal",
1124
- "env": {
1125
- "DEBUG": "strudel:*"
1126
- }
1127
- }
1128
- ```
1129
-
1130
- **Playwright Debugging**
1131
- ```typescript
1132
- // In StrudelController.ts
1133
- this.browser = await chromium.launch({
1134
- headless: false, // See the browser
1135
- devtools: true, // Open DevTools
1136
- slowMo: 100 // Slow down actions
1137
- });
1138
- ```
1139
-
1140
- ### Performance Monitoring
1141
-
1142
- The server includes built-in performance monitoring:
1143
-
1144
- ```typescript
1145
- // Access performance metrics
1146
- You: Show me performance metrics
1147
-
1148
- Claude: Performance Report:
1149
- {
1150
- "averageLatency": {
1151
- "init": "3.2s",
1152
- "write": "52ms",
1153
- "play": "105ms",
1154
- "analyze": "18ms"
1155
- },
1156
- "cacheHitRate": "85%",
1157
- "totalOperations": 1247,
1158
- "bottlenecks": [
1159
- {"tool": "init", "avgTime": 3200, "calls": 1},
1160
- {"tool": "write", "avgTime": 52, "calls": 156}
1161
- ]
1162
- }
1163
- ```
1164
-
1165
- ### Contributing Guidelines
1166
-
1167
- 1. **Fork the repository**
1168
- ```bash
1169
- git clone https://github.com/YOUR_USERNAME/live-coding-music-mcp.git
1170
- ```
1171
-
1172
- 2. **Create a feature branch**
1173
- ```bash
1174
- git checkout -b feature/my-new-feature
1175
- ```
1176
-
1177
- 3. **Make your changes**
1178
- - Follow existing code style
1179
- - Add tests for new features
1180
- - Update documentation
1181
- - Ensure all tests pass
1182
-
1183
- 4. **Commit with meaningful messages**
1184
- ```bash
1185
- git commit -m "feat: Add support for custom scale generation"
1186
- ```
1187
-
1188
- Follow [Conventional Commits](https://www.conventionalcommits.org/):
1189
- - `feat:` New feature
1190
- - `fix:` Bug fix
1191
- - `docs:` Documentation changes
1192
- - `refactor:` Code refactoring
1193
- - `test:` Adding tests
1194
- - `chore:` Maintenance tasks
1195
-
1196
- 5. **Push and create PR**
1197
- ```bash
1198
- git push origin feature/my-new-feature
1199
- ```
1200
-
1201
- Then create a Pull Request on GitHub with:
1202
- - Clear description of changes
1203
- - Link to related issues
1204
- - Screenshots/examples if relevant
1205
-
1206
- ### Release Process
708
+ Quick links:
709
+ - [Setup](DEVELOPMENT.md#setup) — `git clone` to `npm test`
710
+ - [Adding new tools](DEVELOPMENT.md#adding-new-tools) — module pattern + envelope helpers
711
+ - [Release process](DEVELOPMENT.md#release-process) — `gh release create` triggers the publish workflow
712
+ - [Contributing](DEVELOPMENT.md#contributing) — commit conventions and PR flow
1207
713
 
1208
- ```bash
1209
- # 1. Update version in package.json
1210
- npm version patch # or minor/major
1211
-
1212
- # 2. Update CHANGELOG.md
1213
- # Add entry for new version
1214
-
1215
- # 3. Build and test
1216
- npm run build
1217
- npm test
1218
- npm run test:integration
1219
-
1220
- # 4. Commit version bump
1221
- git add .
1222
- git commit -m "chore: Bump version to X.Y.Z"
1223
-
1224
- # 5. Create git tag
1225
- git tag vX.Y.Z
1226
-
1227
- # 6. Push to GitHub
1228
- git push origin main --tags
1229
-
1230
- # 7. Publish to npm (if you have access)
1231
- npm publish --access public
1232
-
1233
- # 8. Create GitHub release
1234
- gh release create vX.Y.Z --generate-notes
1235
- ```
1236
-
1237
- ### Docker Development
1238
-
1239
- ```bash
1240
- # Build development image
1241
- docker build -t live-coding-music-mcp:dev .
1242
-
1243
- # Run with volume mount for hot reload
1244
- docker run -it --rm \
1245
- -v $(pwd)/src:/app/src \
1246
- -v $(pwd)/patterns:/app/patterns \
1247
- live-coding-music-mcp:dev
1248
-
1249
- # Run tests in container
1250
- docker run -it --rm live-coding-music-mcp:dev npm test
1251
- ```
1252
-
1253
- ### Environment Variables
1254
-
1255
- ```bash
1256
- # Logging level
1257
- LOG_LEVEL=debug # debug, info, warn, error
1258
-
1259
- # Performance monitoring
1260
- ENABLE_PERF_MONITORING=true
1261
-
1262
- # Pattern storage
1263
- PATTERNS_DIR=./patterns
1264
-
1265
- # Browser configuration
1266
- HEADLESS=false
1267
- BROWSER_TIMEOUT=15000
1268
-
1269
- # Audio analysis
1270
- FFT_SIZE=1024
1271
- SMOOTHING=0.8
1272
- ```
714
+ The [Configuration](#configuration) section above covers runtime config (`config.json`). [ARCHITECTURE.md](ARCHITECTURE.md) covers the system design.
1273
715
 
1274
716
  ## Performance
1275
717
 
@@ -1282,8 +724,8 @@ Measured against the current `StrudelController` cache + Strudel.cc on a develop
1282
724
  | Pattern read (cached) | 10–15 ms |
1283
725
  | Play / pause / stop | 100–150 ms |
1284
726
  | Audio analysis (single FFT) | 10–15 ms |
1285
- | Tempo detection | <100 ms (onset-based; degraded under headless audio) |
1286
- | Key detection | <100 ms (Krumhansl-Schmuckler) |
727
+ | Tempo detection | <100 ms (onset-based; reports poll cadence, not tempo — #322) |
728
+ | Key detection | <100 ms (Krumhansl-Schmuckler, Pearson; bass-register accuracy depends on `fft_size`) |
1287
729
  | Pattern generation | <100 ms (template-based) |
1288
730
  | Process resident memory | ~120–150 MB |
1289
731
 
@@ -1454,7 +896,7 @@ s("bd*4")
1454
896
  .every(8, x => x.sometimes(y => y.fast(2)))
1455
897
  ```
1456
898
 
1457
- ## 🔒 Security
899
+ ## Security
1458
900
 
1459
901
  ### Pattern Validation
1460
902
 
@@ -1463,11 +905,23 @@ All patterns are validated before execution:
1463
905
  - **Eval blocks** are rejected
1464
906
  - **Path traversal** attacks are blocked in PatternStore
1465
907
 
1466
- ### Browser Sandboxing
908
+ ### Browser Isolation
909
+
910
+ Be precise about what this does and does not give you:
911
+
912
+ - **The OS-level Chrome sandbox is disabled.** Chromium is launched with `--no-sandbox` and
913
+ `--disable-setuid-sandbox` ([`src/StrudelController.ts`](src/StrudelController.ts)) for headless
914
+ and container compatibility, where the sandbox otherwise needs `CAP_SYS_ADMIN` or user namespaces.
915
+ This is a deliberate trade-off, not a security feature.
916
+ - **The browser context is a fresh, non-persistent Playwright context** — no profile on disk, no
917
+ cookies or storage carried over between runs, and no `file://` navigation is ever performed.
918
+ - **Resource blocking is a performance optimization, not a security boundary.** Images, fonts, and
919
+ media are aborted to speed up page load; scripts, stylesheets, and network requests from
920
+ strudel.cc are allowed through as normal.
921
+ - **Patterns are validated before execution** (see above), which is the actual pre-execution control.
1467
922
 
1468
- - Playwright runs Chromium in sandbox mode
1469
- - No access to local filesystem from browser context
1470
- - Resource blocking prevents loading external content
923
+ If you need real isolation, run the whole MCP server inside a locked-down container or VM. The
924
+ server does not sandbox itself.
1471
925
 
1472
926
  ### Known Limitations
1473
927
 
@@ -1479,7 +933,7 @@ All patterns are validated before execution:
1479
933
 
1480
934
  Found a vulnerability? Please [open a security issue](https://github.com/williamzujkowski/live-coding-music-mcp/security/advisories/new) or email the maintainer directly. Do not disclose publicly until patched.
1481
935
 
1482
- ## 🐛 Troubleshooting
936
+ ## Troubleshooting
1483
937
 
1484
938
  ### Common Issues
1485
939
 
@@ -1546,7 +1000,7 @@ npm run build
1546
1000
  # Check if server responds
1547
1001
  echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
1548
1002
 
1549
- # Should return JSON with 84 tools (post-v3.0; ~26 after #178 alias removal)
1003
+ # Should return JSON with 28 tools
1550
1004
 
1551
1005
  # Reinstall MCP server in Claude
1552
1006
  claude mcp remove strudel
@@ -1587,7 +1041,7 @@ claude chat
1587
1041
  - Use resource blocking (enabled by default)
1588
1042
 
1589
1043
  #### Patterns not saving
1590
- **Symptom**: `save` command fails or patterns don't persist
1044
+ **Symptom**: `pattern_store({ action: "save" })` fails or patterns don't persist
1591
1045
 
1592
1046
  **Solutions**:
1593
1047
  ```bash
@@ -1655,7 +1109,7 @@ Claude: Browser state:
1655
1109
  - Initialized: true
1656
1110
  - Cached patterns: 2
1657
1111
  - Undo stack depth: 5
1658
- - Last operation: write_pattern (2.5s ago)
1112
+ - Last operation: edit_pattern (2.5s ago)
1659
1113
  ```
1660
1114
 
1661
1115
  **Validate Pattern Syntax**
@@ -1678,53 +1132,31 @@ If you encounter issues not covered here:
1678
1132
  4. **Consult Strudel docs**: [Strudel.cc documentation](https://strudel.cc/learn)
1679
1133
  5. **Create new issue**: Include error messages, OS, Node version, and steps to reproduce
1680
1134
 
1681
- ## 🤝 Contributing
1682
-
1683
- **We need your help!** This project is actively developed and welcomes contributions of all kinds:
1684
-
1685
- ### Ways to Contribute
1686
- - **Report Bugs**: Found an issue? [Open a bug report](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
1687
- - **Suggest Features**: Have ideas? [Create a feature request](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
1688
- - **Improve Docs**: Fix typos, add examples, clarify confusing sections
1689
- - **Write Tests**: Help us improve test coverage
1690
- - **Fix Issues**: Check [open issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) for bugs to fix
1691
- - **Add Features**: Implement new tools or improve existing ones
1692
-
1693
- ### Quick Start for Contributors
1694
- 1. Fork the repository
1695
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
1696
- 3. Make your changes and add tests
1697
- 4. Ensure tests pass (`npm test`)
1698
- 5. Commit with clear messages (`git commit -m 'fix: resolve audio analysis bug'`)
1699
- 6. Push to your fork (`git push origin feature/amazing-feature`)
1700
- 7. Open a Pull Request
1135
+ ## Contributing
1701
1136
 
1702
- **First time contributor?** Look for issues labeled `good-first-issue` or `help-wanted`.
1137
+ PRs welcome — bug fixes, docs, tests, new tools. See **[CONTRIBUTING.md](CONTRIBUTING.md)** for the contribution guide and **[DEVELOPMENT.md](DEVELOPMENT.md)** for setup and workflow.
1703
1138
 
1704
- ### Feedback Welcome
1705
- - Questions? Open a [Discussion](https://github.com/williamzujkowski/live-coding-music-mcp/discussions)
1706
- - Found something confusing? Tell us!
1707
- - Have a use case we haven't considered? Share it!
1139
+ For non-trivial work, open a GitHub issue first ([issue policy in CLAUDE.md](CLAUDE.md#github-issues-workflow)). For typos and small fixes, a PR directly is fine.
1708
1140
 
1709
- We review PRs promptly and welcome contributors of all skill levels. See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed setup instructions.
1141
+ [GitHub Discussions](https://github.com/williamzujkowski/live-coding-music-mcp/discussions) are open for use-case questions and design conversations.
1710
1142
 
1711
- ## 📄 License
1143
+ ## License
1712
1144
 
1713
1145
  **AGPL-3.0-or-later** — see [LICENSE](LICENSE) for the full text.
1714
1146
 
1715
1147
  This project depends on `@strudel/core`, `@strudel/mini`, `@strudel/tonal`, and `@strudel/transpiler`, which are AGPL-3.0 licensed by the upstream [Strudel project](https://codeberg.org/uzu/strudel). Since we `import` from those packages and redistribute the combined work via npm, this project must be distributed under the same copyleft terms. If you fork or redistribute, you must keep the AGPL license and provide source access to any network-accessible users (AGPL §13).
1716
1148
 
1717
- Earlier versions of this package (including `@williamzujkowski/strudel-mcp-server` prior to deprecation) shipped with an MIT declaration — that was incorrect given the AGPL dependencies. v2.0.0 of `@williamzujkowski/live-coding-music-mcp` corrects the license to AGPL-3.0-or-later. v1.0.0 of this package is deprecated; install v2.0.0 or later.
1149
+ Earlier versions of this package (including `@williamzujkowski/strudel-mcp-server` prior to deprecation) shipped with an MIT declaration — that was incorrect given the AGPL dependencies. v2.0.0 of `@williamzujkowski/live-coding-music-mcp` corrects the license to AGPL-3.0-or-later. v1.0.0 of this package is deprecated; install v2.0.0 or later (current: v4.0.0).
1718
1150
 
1719
- ## 🙏 Acknowledgments
1151
+ ## Acknowledgments
1720
1152
 
1721
- - [Strudel.cc](https://strudel.cc) - Amazing live coding environment
1722
- - [TidalCycles](https://tidalcycles.org) - Pattern language inspiration
1723
- - [Anthropic](https://anthropic.com) - Claude AI and MCP protocol
1724
- - [Playwright](https://playwright.dev) - Reliable browser automation
1153
+ - [Strudel.cc](https://strudel.cc) — pattern-based live coding environment (this project is a fan adapter, not affiliated)
1154
+ - [TidalCycles](https://tidalcycles.org) — original pattern language Strudel descends from
1155
+ - [Anthropic](https://anthropic.com) — Claude and the MCP protocol
1156
+ - [Playwright](https://playwright.dev) — browser automation
1725
1157
 
1726
1158
  ---
1727
1159
 
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)
1160
+ **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
1161
 
1730
1162
  *This project is under active development. Core features work, but expect bugs and breaking changes. Not recommended for production use.*