# AGENTS.md ## Strudel Live Coding Assistant Guidelines ### Overview This document provides essential guidelines for AI agents assisting with Strudel live coding. Strudel is a JavaScript-based port of TidalCycles for algorithmic music composition and live coding performance. ### Critical Knowledge Requirements #### 1. Core Syntax Understanding - **NOT JavaScript**: Strudel uses its own pattern-based syntax, not standard JavaScript - **NO variable declarations**: No `const`, `let`, `var`, `export`, `import` - **NO function syntax**: Patterns are composed directly, not stored in functions #### 2. Parallel Pattern Syntax ```javascript // ✅ CORRECT - Multiple patterns in parallel $: sound("bd*4") $: sound("~ sd ~ sd") $: sound("hh*8").gain(0.3) // ❌ WRONG - JavaScript-style const kick = sound("bd*4"); const snare = sound("~ sd ~ sd"); ``` #### 3. Muting Patterns ```javascript // ✅ Mute a pattern (for live performance) _$: sound("bd*4") // underscore mutes // ✅ Active pattern $: sound("bd*4") // dollar sign plays ``` #### 4. Notes and Scales ```javascript // ✅ CORRECT - Using scale degrees with n() $: n("0 2 4 6").scale("C:minor").sound("piano") // ❌ WRONG - Manual note names (this works but is not idiomatic) $: note("c eb g bb").sound("piano") // ✅ Scale variations $: n("0 2 4 <[6,8] [7,9]>").scale("C:minor").sound("piano") ``` #### 5. Common Scale Names - `C:major`, `C:minor` - `A2:minor` (with octave) - `D:dorian`, `G:mixolydian` - `A2:minor:pentatonic` - `F:major:pentatonic` #### 6. Pattern Notation (Mini-notation) ```javascript // Basic patterns "bd ~ sd ~" // kick-rest-snare-rest "bd*4" // four kicks per cycle "bd*<2 4>" // alternating subdivisions "" // alternating sounds "[bd sd]" // both in one beat "bd@3 sd" // bd three times longer "bd!3 sd" // replicate bd three times "[bd ~ sd ~]/2" // slow down by half // Advanced patterns "~ 0 ~ 2 ~ 4 ~ 6" // scale degrees with rests "0*4 2*2 4*2 6*4" // complex subdivisions "0,2,4,6" // chord (simultaneous) ``` #### 7. Sound Sources ```javascript // Drum samples $: sound("bd sd hh oh") // Instrument banks $: sound("bd sd").bank("RolandTR909") // Synthesizers $: n("0 2 4 6").sound("sawtooth") // waveforms $: n("0 2 4 6").sound("piano") // samples $: n("0 2 4 6").sound("gm_acoustic_bass") // GM sounds ``` #### 8. Effects and Modulation ```javascript // Audio effects .gain(0.8) // volume .lpf(800) // low-pass filter .hpf(2000) // high-pass filter .reverb(0.4) // reverb amount .room(0.6) // room reverb .delay(0.25) // delay time .pan(-0.3) // stereo pan (-1 to 1) // Live modulation .gain(sine.range(0.5, 1).slow(4)) // oscillating gain .lpf(sine.range(200, 2000).slow(8)) // filter sweep .pan(sine.range(-0.5, 0.5).slow(6)) // auto-pan ``` #### 9. Time Manipulation ```javascript .slow(2) // half speed (2x longer cycles) .fast(2) // double speed (half-length cycles) .early(0.125) // timing offset .late(0.125) // timing delay ``` #### 10. Probability and Randomness ```javascript .sometimes(rev) // randomly apply reverse .often(x => x.fast(2)) // frequently apply effect .rarely(x => x.gain(0.5)) // rarely apply effect .mask("1 0 1 1") // rhythmic gating ``` ### Documentation Sources Before providing Strudel code, agents should: 1. **Always check official documentation**: https://strudel.cc/ 2. **Reference workshop tutorials**: https://strudel.cc/workshop/ 3. **Verify syntax against examples** in the Strudel REPL ### Common Mistakes to Avoid #### ❌ JavaScript Assumptions ```javascript // WRONG - This is not JavaScript const pattern = sound("bd*4"); export default pattern; import { stack } from "strudel"; ``` #### ❌ Function Declarations ```javascript // WRONG - No function syntax function createBeat() { return sound("bd*4"); } ``` #### ❌ Stack Usage ```javascript // WRONG - stack() doesn't exist in REPL stack( sound("bd*4"), sound("~ sd ~ sd") ) ``` #### ❌ Variable References ```javascript // WRONG - No variable system const kick = sound("bd*4"); kick.gain(0.8); ``` ### ✅ Correct Patterns #### Live Performance Setup ```javascript // Multiple parallel patterns $: sound("bd*4").gain(0.8) $: sound("~ sd ~ sd").gain(0.7) $: sound("hh*8").gain(0.3).hpf(8000) $: n("0 ~ 2 ~ 4 ~ 6 ~").scale("C2:minor").sound("sawtooth").lpf(120) $: n("~ 0 ~ 2 ~ 4 ~ 6").scale("C4:minor").sound("piano").room(0.6) ``` #### Live Coding Effects ```javascript // Instant filter sweep $: sound("bd*4").lpf(sine.range(100, 2000).slow(4)) // Rhythmic gating $: n("0 2 4 6").scale("C:minor").sound("piano").mask("1 0 1 1") // Probability effects $: sound("hh*8").sometimes(rev).often(x => x.gain(0.5)) ``` ### Agent Response Protocol 1. **Read documentation first** when unsure about syntax 2. **Provide working examples** that can be copy-pasted into REPL 3. **Use `$:` prefix** for all patterns 4. **Include muting options** with `_$:` for live performance 5. **Explain mini-notation** when using complex patterns 6. **Test understanding** by referring to official examples ### Git Commit Guidelines - **Use lowercase commit messages**: All commit messages must be written in lowercase ### Development Environment Guidelines - **Never use global npm installs**: Avoid `npm i -g` or `npm install -g` commands - **Use NixOS shells/dev environments**: Always prefer Nix-based development environments for reproducible builds - **Current NixOS version**: 25.05 #### Git Submodules The Strudel codebase is managed as a git submodule in the 'src' directory. To work with the codebase: 1. Initialize submodules: `make submodules-init` 2. Update submodules: `make submodules-update` This ensures the correct version of the Strudel repository is checked out and kept in sync. #### Nix Development Shell Use the following `flake.nix` for Strudel development: ```nix { description = "Strudel development environment"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; in { devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ nodejs_20 pnpm git ]; shellHook = '' echo "Strudel development environment loaded" echo "Node.js: $(node --version)" echo "pnpm: $(pnpm --version)" ''; }; }); } ``` #### Usage **Option 1: Direct Nix commands** 1. **Enter development shell**: ```bash nix develop ``` 2. **Install dependencies**: ```bash pnpm install ``` 3. **Start development server**: ```bash pnpm dev ``` **Option 2: Using Makefile (recommended)** The Makefile provides convenient shortcuts for common development tasks. First, ensure submodules are initialized: ```bash # Initialize and update submodules make update # Install dependencies make install # Start development server make dev # Run tests make test # Run linter make lint # Format code make format # Run all checks make check # Enter Nix shell directly make shell # Show help make help ``` All Makefile commands automatically run within the Nix development environment. ### Live Performance Considerations When creating beats for live performance: - **Each `$:` line is independently controllable** - **Use `_$:` to mute sections during performance** - **Include modulation for evolving sounds** - **Provide multiple variations/sections** - **Keep patterns readable for live modification** ### Example Response Structure ```javascript // MAIN BEAT $: sound("bd*4").gain(0.8) // kick $: sound("~ sd ~ sd").gain(0.7) // snare $: sound("hh*8").gain(0.3) // hats $: n("0 ~ 2 ~ 4 ~ 6 ~").scale("C2:minor").sound("sawtooth") // bass // LIVE VARIATIONS (comment/uncomment as needed) // $: sound("bd*4").lpf(sine.range(200, 2000).slow(8)) // filter sweep // $: sound("~ sd ~ sd").mask("1 0 1 1") // gated snare ``` This structure allows for immediate use and live manipulation in the Strudel REPL environment.