Files
strudel/AGENTS.md

8.3 KiB

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

// ✅ 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

// ✅ Mute a pattern (for live performance)
_$: sound("bd*4")  // underscore mutes

// ✅ Active pattern
$: sound("bd*4")   // dollar sign plays

4. Notes and Scales

// ✅ 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)

// Basic patterns
"bd ~ sd ~"        // kick-rest-snare-rest
"bd*4"             // four kicks per cycle
"bd*<2 4>"         // alternating subdivisions
"<bd sd>"          // 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

// 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

// 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

.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

.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

// WRONG - This is not JavaScript
const pattern = sound("bd*4");
export default pattern;
import { stack } from "strudel";

Function Declarations

// WRONG - No function syntax
function createBeat() {
    return sound("bd*4");
}

Stack Usage

// WRONG - stack() doesn't exist in REPL
stack(
    sound("bd*4"),
    sound("~ sd ~ sd")
)

Variable References

// WRONG - No variable system
const kick = sound("bd*4");
kick.gain(0.8);

Correct Patterns

Live Performance Setup

// 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

// 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:

{
  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:

    nix develop
    
  2. Install dependencies:

    pnpm install
    
  3. Start development server:

    pnpm dev
    

Option 2: Using Makefile (recommended) The Makefile provides convenient shortcuts for common development tasks. First, ensure submodules are initialized:

# 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

// 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.