Skip to content

Features

Producer Pal is an AI-powered music production assistant for Ableton Live — an Ableton MCP server that lets any AI read, create, and modify your Live Set. Tell the AI what you want and it uses 22 specialized tools to read, create, and modify tracks, clips, devices, and more in your Live Set.

It works with virtually any AI, including its built-in Chat UI, desktop apps like Claude Desktop and Codex, CLI tools, and web apps.

Get started →

Core Tools

🔧 Connect (ppal-connect)

  • Establish the connection with Ableton Live (required before using other tools)
  • Summarizes the state of the current Live Set
  • Returns a skill set that teaches the AI how to use Producer Pal effectively. Standard skills cover the full feature set. Small model mode provides simplified skills and schemas for less capable models.

(no parameters)

🔧 Context (ppal-context)

  • Read and write project memory — persistent notes that help the AI understand your goals across conversations
Parameters
ParameterTypeDescription
action"read" |
"write"
(required)
read: view memory | write: replace memory
contentstringcontent to write (required for write)

Session Tools

🔧 Playback (ppal-playback)

  • Start/stop playback in Session or Arrangement view
  • Play specific scenes or clips
  • Set loop points and playback position
  • Jump to arrangement locators by ID or name
  • Set loop start/end using locators
  • Control which tracks follow the Arrangement
  • Stop all clips or specific track clips
Parameters
ParameterTypeDescription
action"play-arrangement" |
"update-arrangement" |
"play-scene" |
"play-session-clips" |
"stop-session-clips" |
"stop-all-session-clips" |
"stop"
(required)
play-arrangement: from startTime
update-arrangement: modify loop
play-scene: all clips in scene
play-session-clips: by id(s) or slot(s)
stop-session-clips: by id(s) or slot(s)
stop-all-session-clips: all
stop: session and arrangement
startTimestringbar|beat position in arrangement (song meter)
startLocator 🐘stringlocator ID or name for start position (e.g., locator-0 or Verse)
loopbooleanarrangement loop?
loopStartstringbar|beat position (song meter)
loopStartLocator 🐘stringlocator ID or name for loop start
loopEndstringbar|beat position (song meter)
loopEndLocator 🐘stringlocator ID or name for loop end
idsstringcomma-separated ID(s) for clip operations
slotsstringsession clip slot(s), trackIndex/sceneIndex format, comma-separated (e.g., '0/1' or '0/1,2/3')
sceneIndexinteger 0-based scene index for play-scene

🐘 = large model only (hidden in small model mode)

🔧 Library (ppal-library)

Requires Live 12.4+

The library tools require Ableton Live 12.4 or later. On older versions they return an error explaining the requirement. Use the version of Max bundled with Live, or make sure your standalone Max is up to date. See Troubleshooting for details.

  • Search Live's browser library by name, tags, content kind, device kind, or source category (User Library, Pack, Built-in, Cloud, Plugin)
  • Also includes the user-configured sample folder when set, with results merged and de-duplicated against Live's library
  • Sort by use_count (Live's persistent usage counter — surfaces what you actually use most), mod_date, or name
  • Enumerate available tags with action: "listTags" so the AI can discover the tag vocabulary on your machine
Parameters
ParameterTypeDescription
action"search" |
"listTags" |
"listCategories" 🐘 |
"searchBatch" 🐘 |
"listPlugins" 🐘 |
"findSimilar" 🐘 |
"findDuplicates" 🐘
search: filter library items (default) | listTags: enumerate available tags | listCategories: browse Live's category taxonomy (Sounds, Drums, Genres, …); pass category to drill into its tags | searchBatch: run many filtered searches in one call (e.g. build a drum kit), results grouped per query | listPlugins: list installed VST/VST3/AU plugins Live knows about (filter with query, vendor, format, deviceKind, subcategory) | findSimilar: rank samples by audio similarity to a seed sample (similarTo); combine with the search filters to constrain candidates | findDuplicates: group library samples with identical audio (re-shipped duplicates), scoped by the search filters
queries 🐘arraysearchBatch only: array of query objects, each with the same filters as a single search (query, tags, kind, type, deviceKind, source, inFolder, sort, limit, verifyPaths) plus an optional label; results are returned in order, grouped per query (capped at 20)
querystringname substring (search: supports * as a multi-character wildcard; listPlugins: plain case-insensitive substring)
tagsstringcomma-separated tag names; results must match ALL listed tags (search only)
kind"audio" |
"midi" |
"live-clip" 🐘 |
"preset" |
"device-group" |
"m4l-device" 🐘 |
"live-set" 🐘 |
"plugin" 🐘 |
"image" 🐘 |
"video" 🐘 |
"folder" 🐘
content kind filter (search only; default: audio — the only kind loadable into clips/Simpler today, others are discovery-only). audio=.wav/.aif/.mp3/etc. samples | midi=.mid files PLUS MIDI Live clips (.alc), so it covers all MIDI content | live-clip=all .alc Ableton clips (MIDI+audio; each result reports subtype) | preset=instrument/effect presets | device-group=.adg device chains (racks) | m4l-device=.amxd Max for Live devices | live-set=.als project files | plugin=VST/AU specs and presets | image/video=media assets | folder=directory entries (a DB row type, distinct from source:sampleFolder)
type"loop" |
"oneshot" |
"impulse-response"
playback type filter (search only): loop=loops | oneshot=one-shots (e.g. a kick) | impulse-response=convolution IRs. Also reported per result as type.
category 🐘stringlistCategories only: a top-level category name (from listCategories with no category) to drill into; returns its tag names, each usable as a tags filter
similarTo 🐘stringfindSimilar only: absolute path of a seed sample (e.g. a path from a prior search) to rank other samples by audio similarity. Combine with the search filters to constrain candidates — e.g. similarTo a kick + tags=Kick for 'more kicks like this one'. Each result carries a similarity score (-1 to 1, ~1 = very similar).
deviceKind 🐘"instrument" |
"audiofx" |
"midifx"
device classification filter (search + listPlugins; for listPlugins only instrument/audiofx apply)
vendor 🐘stringvendor/manufacturer substring, case-insensitive (listPlugins only)
format 🐘"VST" |
"VST3" |
"AU"
plugin binary format filter (listPlugins only)
subcategory 🐘stringsubcategory substring filter, case-insensitive (listPlugins only; matches any of a plugin's genre/role tags, e.g. reverb, delay, synth). Also reported per result as subcategories.
source"sampleFolder" |
"user" |
"pack" |
"builtin" |
"cloud" |
"plugin"
where the file lives (search only). sampleFolder=user-configured sample folder on disk (bypasses Live's DB) | user=your User Library | pack=installed Packs (factory + 3rd-party) | builtin=Ableton's Core Library | cloud=Cloud-stored items | plugin=installed VST/AU/etc. plugins
inFolderstringabsolute folder path; returns only immediate children of that folder (search only). Composes with other filters. Case-insensitive (ASCII). Unresolvable paths return no results with a reason explaining the path wasn't found.
sort 🐘"use_count" |
"mod_date" |
"name"
sort order (search only); defaults to use_count desc
verifyPaths 🐘booleansearch only: stat each result's path and add pathExists (true/false) so you can skip files moved/deleted since Live last indexed. Off by default (one filesystem check per result).
limitnumbermax results; defaults to 50 (search) or 200 (listTags)

🐘 = large model only (hidden in small model mode)

🔧 Select (ppal-select)

  • Read current selection and view state (when no arguments)
    • Returns only non-null fields: selected track, scene, clip, device
    • Rich object shapes with IDs, types, and context (slot, path, etc.)
  • Update selection and returns only relevant fields
    • Select any object by ID (auto-detects track/scene/clip/device)
    • Select tracks by index/category, scenes by index
    • Select clips by slot position (e.g., 0/3)
    • Select devices by path (e.g., t0/d1)
    • Switch between Session and Arrangement views
    • Auto-switches to session view for scene/clipSlot selection
    • Detail views auto-managed: clip detail opens on clip selection, device detail on device selection
Parameters
ParameterTypeDescription
idstringselect by ID (auto-detects track/scene/clip/device)
trackIndexinteger 0-based track index
trackType"return" |
"master"
omit for audio/midi tracks, or: return, master
sceneIndexinteger 0-based scene index
slotstringsession clip slot: trackIndex/sceneIndex (e.g., '0/3')
devicePathstringselect device by path (e.g. t0/d1)
openPluginWindow 🐘booleanopen (true) or close (false) a plug-in's (VST/AU) floating editor window; targets the device given by id or devicePath
view"session" |
"arrangement"
main view

🐘 = large model only (hidden in small model mode)

Action Tools

🔧 Delete (ppal-delete)

  • Remove tracks, return tracks, scenes, clips, or devices
  • Bulk delete multiple objects
Parameters
ParameterTypeDescription
idsstringcomma-separated ID(s) to delete (must be same type)
pathstringcomma-separated device/drum-pad paths to delete (e.g., 't0/d1', 't1/d0/pC1/d0', 't1/d0/pC1')
type"track" |
"scene" |
"clip" |
"device" |
"drum-pad"
(required)
type of objects to delete

🔧 Duplicate (ppal-duplicate)

  • Copy tracks, scenes, clips, or devices
  • Create multiple copies at once
  • Copy clips anywhere in the Session, Arrangement, or from Session to Arrangement
    • Position in the Arrangement by bar|beat or locator
    • Auto-tile clips to fill longer arrangement durations
  • Apply transforms to each duplicated clip (e.g. transpose copies, vary velocities) without a separate update step
  • Stack MIDI variations on take lanes with takeLane: "new" + transforms — audition alternates at the same arrangement position
  • Copy devices to any track, return track, or rack chain
  • Route duplicated tracks to source instrument for MIDI layering

Note: Return tracks and devices on return tracks cannot be duplicated (Live API limitation).

Parameters
ParameterTypeDescription
idstring object to duplicate
type"track" |
"scene" |
"clip" |
"device"
(required)
type of object to duplicate
namestringname (comma-separated when duplicating multiple)
colorstring#RRGGBB (comma-separated when duplicating multiple, cycles)
count 🐘integer number of copies (tracks/scenes only, ignored for clips/devices)
withoutClips 🐘booleanexclude clips?
withoutDevices 🐘booleanexclude devices?
arrangementStartstringarrangement bar|beat position(s) for clips/scenes, comma-separated for multiple (e.g., '1|1' or '1|1,2|1,3|1'). Song meter
locator 🐘stringarrangement locator ID(s) or name(s), comma-separated for multiple (e.g., 'locator-0' or 'Verse' or 'locator-0,Chorus')
arrangementLengthstringduration: Nbar (e.g., '4bar'), n<fraction> note value (e.g., 'n/4'), or Nbar+n<fraction> (e.g., '1bar+n/4'). Auto-fills with loops; song meter
toSlotstringsession destination clip slot(s), trackIndex/sceneIndex format, comma-separated for multiple (e.g., '0/1' or '0/1,2/3')
toPathstringdevice destination path(s), comma-separated for multiple (e.g., 't1/d0' or 't1/d0,t2/d0')
routeToSource 🐘booleanroute new track to source's instrument? (for MIDI layering/polyrhythms)
transforms 🐘stringtransform expressions (broadcast across copies; clips only); newline-separated for multiple. Use clip.index / clipseq() for per-copy variation
takeLane 🐘stringarrangement take lane (MIDI clips only): omit/0 = main lane, 1+ = that lane (auto-created), "new" = append a fresh lane for a variation
takeLaneName 🐘stringname for a take lane newly created by this call

🐘 = large model only (hidden in small model mode)

Live Set Tools

🔧 Read Live Set (ppal-read-live-set)

  • Get complete Live project overview
  • View all tracks, scenes, and clips at once
  • See tempo, time signature, and scale settings
  • View arrangement locators with times and names
  • Check what's playing and track states
Parameters
ParameterTypeDescription
includearray of:
"tracks" |
"scenes" |
"routings" |
"mixer" |
"color" |
"locators" 🐘 |
"*" 🐘
tracks, scenes = lists. routings, mixer, color = detail (use with tracks/scenes). locators = arrangement markers. "*" = all

🐘 = large model only (hidden in small model mode)

🔧 Update Live Set (ppal-update-live-set)

  • Change tempo, time signature, scale
  • Create, rename, or delete arrangement locators
Parameters
ParameterTypeDescription
temponumber BPM
timeSignaturestringN/D (4/4)
scalestring"Root ScaleName" ("C Major", "F# Minor", "Bb Dorian"). Empty string disables scale
locatorOperation 🐘"create" |
"delete" |
"rename"
Locator operation
locatorId 🐘stringLocator ID for delete/rename (e.g. locator-0). Positional — shifts if locators are added/removed, so prefer locatorTime or locatorName
locatorTime 🐘stringBar|beat position, song meter (required for create, alt ID for delete/rename)
locatorName 🐘stringName for create/rename, or name-match filter for delete

🐘 = large model only (hidden in small model mode)

Track Tools

🔧 Create Track (ppal-create-track)

  • Add MIDI, audio, or return tracks
  • Position tracks exactly where you want
  • Set initial mute/solo/arm states
Parameters
ParameterTypeDescription
trackIndexinteger0-based index, -1 or omit to append
count 🐘integer number to create
namestringname for all, or comma-separated for each
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than count)
type"midi" |
"audio" |
"return"
type
mute 🐘booleanmuted?
solo 🐘booleansoloed?
arm 🐘booleanrecord armed?

🐘 = large model only (hidden in small model mode)

🔧 Read Track (ppal-read-track)

  • Get detailed track information
  • View all clips in Session and Arrangement
  • List take lanes and their clips (with the arrangement-clips include)
  • See devices, routing options, and drum pad mappings
  • Check track states (muted, soloed, armed)
  • View mixer properties: gain, pan, panning mode, and send levels
Parameters
ParameterTypeDescription
trackIdstringprovide this or trackType/trackIndex
trackType"return" |
"master"
return or master (omit for audio/midi tracks, which have independent trackIndexes)
trackIndexinteger 0-based index
includearray of:
"session-clips" |
"arrangement-clips" |
"notes" |
"timing" |
"sample" |
"devices" |
"drum-map" |
"routings" |
"available-routings" 🐘 |
"mixer" |
"color" |
"*" 🐘
session-clips, arrangement-clips = clip lists (arrangement-clips also lists take lanes). notes, timing, sample = clip detail (use with clips). devices, drum-map, routings, available-routings, mixer = track data. color = track + clip color. "*" = all

🐘 = large model only (hidden in small model mode)

🔧 Update Track (ppal-update-track)

  • Change track gain (volume), panning, and send levels
  • Change mute, solo, arm, I/O routings, and monitoring state
  • Change track name and color
  • Update multiple tracks at once
Parameters
ParameterTypeDescription
idsstring comma-separated track ID(s) to update
namestringname for all, or comma-separated for each (extras keep existing name), ideally unique
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than ids)
gainDbnumber track gain in dB
pannumber pan: -1 (left) to 1 (right)
panningMode 🐘"stereo" |
"split"
panning mode: stereo or split
leftPan 🐘number left channel pan in split mode (-1 to 1)
rightPan 🐘number right channel pan in split mode (-1 to 1)
mutebooleanmuted?
solobooleansoloed?
armbooleanrecord armed?
inputRoutingTypeId 🐘stringfrom availableInputRoutingTypes, set before channel
inputRoutingChannelId 🐘stringfrom availableInputRoutingChannels
outputRoutingTypeId 🐘stringfrom availableOutputRoutingTypes, set before channel
outputRoutingChannelId 🐘stringfrom availableOutputRoutingChannels
monitoringState 🐘"in" |
"auto" |
"off"
input monitoring
sendGainDb 🐘number send gain in dB, requires sendReturn
sendReturn 🐘stringreturn track: exact name (e.g., "A-Reverb") or letter (e.g., "A")

🐘 = large model only (hidden in small model mode)

Scene Tools

🔧 Create Scene (ppal-create-scene)

  • Add new scenes at any position
  • Set scene name, color, tempo, and time signature
  • Scenes can follow song tempo or have their own
  • Ability to capture currently playing clips into a new scene
Parameters
ParameterTypeDescription
sceneIndexinteger 0-based index for new scene(s), shifts existing scenes. Required when capture=false, optional when capture=true
count 🐘integer number to create
capture 🐘booleancopy playing session clips instead of creating empty?
namestringname for all, or comma-separated for each
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than count)
tempo 🐘numberBPM (-1 disables when capturing)
timeSignature 🐘stringN/D (4/4) or "disabled" when capturing

🐘 = large model only (hidden in small model mode)

🔧 Read Scene (ppal-read-scene)

  • View scene details and all its clips
  • Check which clips are playing/triggered
  • See scene tempo and time signature
Parameters
ParameterTypeDescription
sceneIdstringprovide this or sceneIndex
sceneIndexinteger 0-based index
includearray of:
"clips" |
"notes" |
"sample" |
"timing" |
"warp" |
"color" |
"*"
clips = clip list. notes, sample, timing, warp = clip detail (use with clips). color = scene + clip color. "*" = all

🔧 Update Scene (ppal-update-scene)

  • Change scene name, color, tempo, and time signature
  • Update multiple scenes at once
Parameters
ParameterTypeDescription
idsstring comma-separated scene ID(s) to update
namestringname for all, or comma-separated for each (extras keep existing name)
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than ids)
temponumberBPM (-1 disables)
timeSignaturestringN/D (4/4) or "disabled"

Clip Tools

🔧 Create Clip (ppal-create-clip)

  • Generate MIDI clips with notes, velocities, and timing using custom notation
  • Place clips in Session slots or Arrangement timeline
  • Place arrangement clips on take lanes with takeLane
  • Support for probability, velocity ranges, and complex rhythms
  • Apply transforms to shape notes with math expressions
  • Auto-create scenes as needed
Parameters
ParameterTypeDescription
slotstringsession clip slot(s): trackIndex/sceneIndex, both 0-based (scene 1 = index 0), comma-separated (e.g., '0/0' or '0/0,0/2,0/5')
trackIndexinteger 0-based track index (arrangement clips)
arrangementStartstringarrangement clip bar|beat position(s), comma-separated for multiple (e.g., '1|1' or '1|1,2|1,3|3'). Song meter
namestringname for all, or comma-separated for each (indexed: session positions first, then arrangement)
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than positions)
timeSignaturestringN/D (4/4), default: global time signature
startstringbar|beat position where loop/clip region begins (clip meter)
lengthstringduration: Nbar (e.g., '4bar'), n<fraction> note value (e.g., 'n/4'), or Nbar+n<fraction> (e.g., '1bar+n/4'). Clip meter. Default: next full bar after latest note
loopingbooleanenable looping for the clip
firstStart 🐘stringbar|beat playback start (looping clips, when different from start; clip meter)
notesstringMIDI in bar|beat notation: v0-127 n<dur> [p0-1] note(s) bar|beat(s) - MIDI clips only
transforms 🐘stringtransform expressions (parameter: expression per line)
sampleFilestringabsolute path to audio file - audio clips only
auto 🐘"play-scene" |
"play-clip"
auto-play session clips (play-scene keeps scene in sync)
takeLane 🐘stringarrangement take lane: omit/0 = main lane, 1+ = that lane (auto-created), "new" = append a fresh lane (for variations)
takeLaneName 🐘stringname for a take lane newly created by this call

🐘 = large model only (hidden in small model mode)

🔧 Read Clip (ppal-read-clip)

  • Get detailed info about any clip in Session or Arrangement
  • Read MIDI notes in custom notation (C3, D#4, etc.)
  • Get audio clip gain, pitch, warp settings, and sample info
Parameters
ParameterTypeDescription
clipIdstringprovide this or slot
slotstringsession clip slot: trackIndex/sceneIndex (e.g., '0/3'). provide this or clipId
includearray of:
"sample" |
"notes" |
"color" |
"timing" |
"warp" 🐘 |
"*" 🐘
notes = MIDI data. timing = loop/start/end markers. sample = audio file info. warp = warp settings. color. "*" = all

🐘 = large model only (hidden in small model mode)

🔧 Update Clip (ppal-update-clip)

  • Change clip name, color, and loop settings
  • Add/remove MIDI notes using custom notation
  • Apply transforms to modify existing notes and audio properties (a different transform per clip when updating multiple)
  • Change audio clip gain, pitch shift, and warp settings
  • Move clips and change their length in the Arrangement
  • Split arrangement clips at specified positions
  • Update multiple clips at once
Parameters
ParameterTypeDescription
idsstring comma-separated clip ID(s) to update
namestringname for all, or comma-separated for each (extras keep existing name)
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than ids)
timeSignaturestringN/D (4/4)
startstringbar|beat position where loop/clip region begins (clip meter)
lengthstringduration: Nbar (e.g., '4bar'), n<fraction> note value (e.g., 'n/4' = quarter), or Nbar+n<fraction> (e.g., '1bar+n/4'); clip meter
loopingbooleanenable looping for the clip
duplicateLoopbooleandouble the clip length and copy existing notes (and automation envelopes) into the new half (Live's Duplicate Loop). MIDI clips only. Composes with edits in a defined order: start/length/firstStart set the loop region first (select a portion to double; any content past that region is pushed later, not deleted), preTransforms edit the source, then the double; notes/transforms/code then apply across the full doubled clip
firstStart 🐘stringbar|beat playback start (looping clips, when different from start; clip meter)
arrangementStartstringbar|beat position (song meter) to move arrangement clip (arrangement clips only)
arrangementLengthstringduration: Nbar (e.g., '4bar'), n<fraction> note value (e.g., 'n/4'), or Nbar+n<fraction> (e.g., '1bar+n/4'). Arrangement clips only; song meter
toSlotstringtrackIndex/sceneIndex to move session clip (e.g., '2/3')
split 🐘stringcomma-separated bar|beat split positions, measured from the clip's start (1|1 = clip start, NOT song time) (e.g., '2|1, 3|1') - max 32 points, arrangement clips only; song meter
gainDbnumber audio clip gain in decibels (ignored for MIDI)
pitchShiftnumber audio clip pitch shift in semitones, supports decimals (ignored for MIDI)
warpMode"beats" |
"tones" |
"texture" |
"repitch" |
"complex" |
"pro"
audio clip warp mode (ignored for MIDI)
warpingbooleanaudio clip warping on/off (ignored for MIDI)
notesstringMIDI notes in bar|beat notation: v0-127 n<dur> [p0-1] note(s) bar|beat(s) - MIDI clips only. MERGES into existing notes (overwrites at same pitch+start - restate a note to edit it in place). To delete/move existing notes or replace a region use preTransforms; don't rewrite the whole clip
transforms 🐘stringtransform expressions applied AFTER merging notes (broadcast across ids); newline-separated for multiple. Use clip.index / clipseq() for per-clip variation
preTransformsstringtransform expressions applied to EXISTING notes BEFORE merging any new notes (broadcast across ids); clear or edit notes already in the clip. v0 deletes (zero velocity): clear a whole bar ('3|: v0', | wildcard avoids spilling onto the next downbeat), a span ('1|1-2|1: v0'), or all ('v0'); also remap a drum lane ('C1: C4'). Works with or without notes
quantizenumber MIDI quantize strength 0-1 (1 = full snap); snaps note starts to quantizeGrid (default 1/16). MIDI clips only
quantizeGrid"1/4" |
"1/8" |
"1/8T" |
"1/8+1/8T" |
"1/16" |
"1/16T" |
"1/16+1/16T" |
"1/32" |
"n/4" |
"n/8" |
"n/12" |
"n/16" |
"n/24" |
"n/32"
grid that note starts snap to: 1/16 (default), 1/8, 1/4, 1/8T, 1/16T, 1/32; n/N note values also accepted (n/12=1/8T, n/24=1/16T); mixed grids 1/8+1/8T and 1/16+1/16T are enum-only
quantizePitch 🐘stringlimit quantization to specific pitch (e.g., C3, D#4)

🐘 = large model only (hidden in small model mode)

Device Tools

🔧 Create Device (ppal-create-device)

  • Add native Live devices (instruments, MIDI effects, audio effects)
  • Place devices on any track type: MIDI, audio, return, or master
  • Position devices at a specific index in the device chain
  • Create devices inside rack chains or drum pads using path notation
  • List the native Live devices
  • Load a sample into a Simpler instrument via params: [{name: "sample", value: "<path>"}], and set its level with {name: "gainDb", value: <dB>} (new in Live 12.4)
Parameters
ParameterTypeDescription
deviceNamestringdevice name, omit to list available devices
pathstringinsertion path(s), required with deviceName, comma-separated for multiple (e.g., 't0' or 't0,t1,t0/d0/c0')
namestringname for all, or comma-separated for each
paramsarrayapplied after creation — array of {name, value}. name = param name or read-device id; value in display units (enum string, note name, number). For a Drum Rack, prefix the name with a pad path to address a pad's device, e.g. {name:'pC1/d0/sample', value:'<abs file path>'} loads a sample into pad C1 (auto-creates the pad's Simpler) — build a full kit in one call

🔧 Read Device (ppal-read-device)

  • Get detailed info about any device, including inside rack chains and drum pad chains
  • List device parameter names and values (the state of knobs, dials, etc)
Parameters
ParameterTypeDescription
deviceIdstringDevice ID to read
pathstringpath (e.g., 't1/d0', 't1/d0/c0', 't1/d0/pC1', 't1/d0/rc0')
includearray of:
"actions" |
"chains" |
"drum-map" |
"drum-pads" 🐘 |
"params" |
"param-values" |
"return-chains" 🐘 |
"sample" |
"options" |
"*" 🐘
chains, return-chains, drum-pads = rack contents (use maxDepth). params, param-values = parameters. drum-map = note names. sample = Simpler sample file path (flat top-level field; gainDb and other sample params are in params). actions = device-specific actions for update-device (name, signature, description). options = valid pseudo-param values (paramOptions) + dynamic catalogs for specialized devices (IR files, sidechain sources, wavetables) + Wavetable mod routes. "*" = all
maxDepthinteger Device tree depth for chains/drum-pads. 0=chains only with deviceCount, 1=direct devices, 2+=deeper
paramSearchstringFilter parameters by case-insensitive substring match on name

🐘 = large model only (hidden in small model mode)

🔧 Update Device (ppal-update-device)

  • Change device name
  • Change device parameter values (control knobs, dials, etc)
  • Update multiple devices at once
  • Move devices anywhere else in the Live Set, including into racks / wrapping in a new rack
  • Create, load, delete, and randomize rack macros variations
  • A/B Compare with supported devices
  • Control chain and drum pad mute and solo state
  • Change the choke group and output MIDI note of drum chains
  • Load a sample into a Simpler instrument via params: [{name: "sample", value: "<path>"}], and set its level with {name: "gainDb", value: <dB>} (new in Live 12.4)
Parameters
ParameterTypeDescription
idsstringcomma-separated ID(s) to update (device, chain, or drum pad)
pathstringcomma-separated path(s) (e.g., 't1/d0', 't1/d0/c0', 't1/d0/pC1')
toPathstringmove to path (e.g., 't2', 't0/d0/c1', 't0/d0/pD1')
namestringname for all, or comma-separated for each (extras keep existing name, not drum pads)
paramsarrayarray of {name, value}. name = param name or read-device id; value in display units (enum string, note name, number). For a Drum Rack target, prefix the name with a pad path, e.g. {name:'pC1/d0/sample', value:'<abs file path>'} sets pad C1's sample (auto-creates the pad's Simpler)
actions 🐘arrayDevice-specific action(s), function-call syntax: bare name or name(args). E.g. "reverse", "warpAs(4)", "setModulation('Osc 1 Pos','Env 2',0.5)"
macroVariation 🐘"create" |
"load" |
"delete" |
"revert" |
"randomize"
Rack only: create/load/delete/revert variation, or randomize macros. load/delete require macroVariationIndex. create always appends.
macroVariationIndex 🐘integer Rack only: variation index for load/delete operations (0-based)
macroCount 🐘integer Rack only: set visible macro count (0-16)
abCompare 🐘"a" |
"b" |
"save"
AB Compare: switch to 'a' or 'b' preset, or 'save' current to other slot
mutebooleanmute state (chains/drum pads only)
solobooleansolo state (chains/drum pads only)
colorstring#RRGGBB for all, or comma-separated for each (cycles if fewer than ids; chains only)
chokeGroup 🐘integer choke group 0-16, 0=none (drum chains only)
mappedPitch 🐘stringoutput MIDI note e.g. 'C3' (drum chains only)
wrapInRack 🐘booleanWrap device(s) in a new rack (auto-detects type from device)

🐘 = large model only (hidden in small model mode)

Advanced Tools

🔧 Live API (ppal-live-api)

Direct access to the Ableton Live Object Model for scripting and debugging.

Off by default. Producer Pal's specialized tools are tuned for reliable results across most models. The raw Live API is low-level and can give weaker results out of the box, so it's hidden rather than competing with the focused tools. It's a powerful escape hatch for scripting and advanced workflows, especially with capable coding agents. Enable it on the Setup tab of the Producer Pal Max for Live device. When disabled, MCP clients and the REST API both stop seeing the tool. See the REST API Live API section for the full operation reference and examples.

Parameters
ParameterTypeDescription
pathstringOptional LiveAPI path (e.g., 'live_set tracks 0')
operationsarray Array of operations to execute (max 50)

Custom Music Notation

Producer Pal uses a text-based music notation syntax called bar|beat to work with MIDI clips. Used by Create Clip, Update Clip, and Read Clip. It helps LLMs translate natural language expressions of time to the correct time positions in Ableton Live clips and the arrangement timeline.

  • Pitches: Standard notation (C3 = middle C, F#4, Bb2, etc.)
  • Time positions: bar|beat format (1|1 = first beat, 2|3 = bar 2, beat 3)
  • Durations: absolute note values (n/4 = quarter note, n/8 = eighth, n/12 = eighth triplet); clip length can also use bars (4bar = 4 bars, 1bar+n/4)
  • Time units: a plain "beat" is your meter's beat (a quarter in 4/4, an eighth in 6/8), while note values (n/4, ±n offsets, durations) are absolute — a quarter is a quarter in any meter. arrangementStart and arrangementLength are read in the song's time signature; a clip's own start/length use the clip's time signature, so when they differ the same bar|beat literal means different absolute times.
  • Velocity: Values from 1-127 (or ranges like 80-100)
  • Probability: 0.0 to 1.0 (1.0 = always plays)
  • Bar copying: Copy bars with @2=1 (bar 1→2), ranges with @2-8=1 (bar 1→bars 2-8), or tile patterns with @3-10=1-2 (repeat 2-bar pattern across bars 3-10)

Transforms

Apply complex changes to clips using math expressions via Create Clip, Update Clip, and Duplicate. When updating or duplicating multiple clips at once, one transform string broadcasts across every clip/copy — use clip.index arithmetic or clipseq() inside the string for per-clip variation:

  • Transform MIDI notes: velocity, pitch, timing, duration, probability
  • Transform audio clips: gain, pitch shift
  • Shapes: LFO waveforms (sine, tri, saw), ramps, curves, randomization with arbitrary ranges, choose from sets of values (e.g. chord notes)
  • Context variables: Access note order (note.index), clip metadata (clip.duration, clip.index, clip.position) in expressions
  • Selectors: Target specific pitch ranges (e.g., C3:, C3-C5:) or time ranges (e.g., 1|1-2|4:), or both in either order (e.g., C3 1|1-2|4: or 1|1-2|4 C3:)

Take Lanes

Live's take lanes stack alternate versions of an arrangement clip at the same position — only the active take plays. They're the natural way to audition variations side by side without cluttering the timeline.

  • Target a lane with takeLane on Create Clip and Duplicate: 0 (or omit) = main lane, 1+ = that lane (auto-created up to it), "new" = append a fresh lane.
  • Generate variations with a few Duplicate calls using takeLane: "new" plus transforms to vary each copy.
  • Name a newly created lane with takeLaneName.
  • Read Track lists take lanes (with the arrangement-clips include).
  • Limits: 8 take lanes per track. Duplicating to a take lane is MIDI-only and recreates the clip from notes, so envelope automation isn't preserved. Once placed, take-lane clips are append-only — they can't be split, moved, resized, deleted, or promoted back to the main lane through tools, and Producer Pal can't pick the active take. All of that stays in Live's UI. Expand the take-lane arrow on a track header to see them.

Network Control

Control Ableton Live from another computer on your local network, no extra setup required. For fully remote control, use web tunnels.

Limitations

  • Automation and envelopes are not supported. Producer Pal cannot read, create, or edit arrangement automation or clip envelopes — parameter values that change over time. Track and device parameters like volume, pan, sends, and knobs can be set to static values, but not automated.
  • VST/AU plug-in internals can't be controlled directly. Producer Pal can open or close a plug-in's editor window, but it cannot read or set the parameters inside a third-party VST/AU plug-in. To control them, map the parameters onto the Live plug-in device using Live's Configure mode (expand the device, click "Configure", then click the controls you want in the plug-in's window); Producer Pal can then set those mapped parameters like any other device parameter. You map them yourself — up to 128 parameters, and not every plug-in parameter is mappable, so pick the ones that matter most.
  • Audio content can't be analyzed or generated. Producer Pal can manage audio clips — set gain, pitch, and warp settings, change clip length, arrange clips in the Arrangement, and load and manage samples on Simpler instruments (including Drum Rack pads) — but it cannot listen to, analyze, or transcribe the audio itself (no detecting notes, key, or tempo from a waveform; no audio-to-MIDI), nor synthesize audio from scratch. These are common requests and are under consideration for a future release.
  • One Drum Rack per track. Drum Racks work in nested structures, but tracks with multiple Drum Racks only use the first one's drum map. Use one Drum Rack per track for predictable results.

Small Model Mode

Adapts Producer Pal for less capable AI models by returning simplified skills and removing advanced parameters from tool schemas. This is an ongoing R&D effort aimed at making local models viable for completely offline, free, and private usage. Enable it in the Chat UI settings or with --small-model-mode on the command line.

Skills

The Connect tool returns a skill set that teaches the AI how to use Producer Pal's custom notation, transforms, device paths, and other conventions. Two variants are available depending on small model mode:

Standard Skills

Time & Note Values

Units: a plain "beat" is your meter's beat — the musical beat (a quarter in x/4, an eighth in x/8). It's what the bar|beat grid, sub-beat decimals, and bare numbers in transform expressions count. Note values (n/4, n/8, ±n offsets, durations, @step) are absolute and meter-invariant: a quarter is a quarter in any meter. Nbar = N of your meter's bars. (Live's internal API unit is the quarter-note "Ableton beat"; you never write it directly.) Bare numbers are valid ONLY in transform expressions — position/duration/length/offset fields require the n form.

Dual meter per call: arrangementStart/arrangementLength (in create-clip, update-clip, and duplicate) resolve against the song time signature, while a clip's own start/firstStart/length (create/update-clip) resolve against the clip time signature. When a clip's meter differs from the song's, the same bar|beat literal denotes different absolute times across those params.

  • Positions: bar|beat — reads left-to-right like the name: 4|2 is bar 4 beat 2, 2|4 is bar 2 beat 4. 1-indexed, meter-relative grid. For one note per bar, step the LEFT number (1|1 2|1 3|1 4|1); to move within a bar, step the right number. Sub-beat placement has two tools for two jobs: a decimal (2|3.5) for partway through a beat (a fraction of the musical beat), and a ±n offset (1|1+n/12 = beat 1 + an eighth triplet, 1|2-n/24) for an exact note value off the grid beat (tuplets, compound-meter placement). The offset attaches to an integer or decimal grid beat — 1|1.5+n/4 is beat 1.5 plus a quarter. They coincide only in x/4 — see the meter note below. A -n offset can pull before a downbeat for a pickup: 1|1-n/4 is a quarter-note pickup ahead of bar 1 (it lands before the clip start, which Live allows); use n/8, n/12, etc. for the lead-in you want. Serialized output uses the exact ±n form for tuplet positions. No bare fractions (beats are 1-indexed — beat 0 is invalid; use a -n pickup instead)
  • Durations and @step intervals: absolute note values (denominator mandatory). n/4 = quarter, n/8 = eighth, n/16 = sixteenth, n/12 = eighth triplet (3 in a quarter), n3/8 = dotted quarter (3 eighths). A quarter is a quarter in any meter
  • Clip length and arrangement durations: Nbar (meter-aware, e.g. 4bar), n<fraction> note value (e.g. n/4 = quarter, n/8 = eighth), or Nbar±n<fraction> mixed — the tail adds or subtracts, so 1bar+n/4 is a bar plus a quarter and 1bar-n/16 is almost a full bar (a bar minus a 16th). Same n fraction grammar everywhere. No bare fractions/integers/decimals
  • Nbar is also valid as a note duration — meter-aware, so 1bar holds one whole bar in any meter (6 grid beats in 6/8, 5 in 5/4). Use it for a single bar-length note; for several notes filling a bar, use a repeat instead (below). Bars use the bare Nbar form — never an n prefix (1bar, not n1bar; n is only for denominator-bearing note values)

In meters other than x/4, the grid beat is NOT a quarter (in 6/8 it's an eighth), so consecutive grid beats are not one note value apart. To place notes a fixed note value apart — e.g. fill a bar with quarter notes — use a repeat pattern 1|1x<count> with a real number for <count> (its step defaults to the current duration, which is meter-safe), not hand-enumerated grid beats: in 6/8, n/4 C1 1|1x3 lands quarters on grid beats 1, 3, 5 (filling the bar), and in 5/4 n/4 C1 1|1x5 fills the bar, while n/4 C1 1|1,2,3 is consecutive eighths in 6/8 (wrong). Same trap for decimals: in 6/8 1|1.5 is half an eighth, 1|1+n/8 a full eighth.

MIDI Syntax

Create MIDI clips using the bar|beat notation syntax:

v0-127 n<duration> [p0-1] note(s) bar|beat(s)

  • v/n/p are prefixes — they apply to the pitches that follow. Vary per pitch by interspersing: v80 C4 v90 G4 (C4 at 80, G4 at 90)
  • Notes emit at time positions (bar|beat)
    • time positions are relative to clip start
    • the beat in bar|beat can be a comma-separated list or repeat pattern. Spaces after commas are fine, and a list item may restate its own bar| — that bar then sticks for the following bare items (1|1,2|1,3 = 1|1 2|1 2|3)
    • Repeat patterns: {bar|beat}x{count}[@{step}] generates sequences. count = how many notes
      • @step uses the same note-value form as n@n/4, @1bar (bare @/4 or @1 is invalid). Defaults to the current duration (legato)
      • 1|1x4@n/4 → 4 notes a quarter apart; n/8 1|1x4 → 4 eighths (step defaults to n value)
      • 1|1x3@n/12 → eighth-note triplets (3 in a quarter); n/16 1|1x16 → 16 sixteenths spanning 4 quarters (a full bar in 4/4)
      • Prefer repeats over hand-listing beats for evenly-spaced notes — the step is a note value, so spacing stays correct in any meter (see Time & Note Values for the meter trap this avoids)
      • Pattern brackets [...]: a cycle of one parameter's values, stepped across notes instead of repeated. Pitch: [C3 E3 G3] 1|1x3@n/4 (or across separate beats, [C3 E3 G3] 1|1 1|2 1|3) plays C3, E3, G3 (a melodic line, not 3× one pitch); (...) is a chord step ([(C3 E3) (D3 F3)] 1|1x2@n/4). Multiple pitch brackets (or a bare pitch + a bracket) layer into chords: C4 [E4 G4 C5] 1|1,2,3,4 is a held C4 under a moving line; [C3 C4] [E3 G3 E4] 1|1,2,3,4 stacks two voices that phase (only pitch layers — v/n/p are last-wins). Velocity/duration/probability: [v100 v60], [n/4 n/8], [p1 p0.5] cycle that value (e.g. [v100 v60 v60 v60] C1 1|1x16@n/16 = accent every 4th hat). A duration bracket with no @step also sets the spacing — the notes gallop ([n/4 n/8] C3 1|1x8 = long-short long-short). One kind per bracket. Zip sibling brackets to vary several at once against the same step: [v80 v100] [C3 E3 G3] 1|1x8@n/8 → eight 8th notes C3 v80, E3 v100, G3 v80, C3 v100, E3 v80, G3 v100, C3 v80, E3 v100 (velocity cycles every 2, pitch every 3 — coprime lengths phase against each other). Each cycle wraps at its own length and persists until you reassign that parameter
  • v<velocity>: 0-127 (default: v100). Range v80-120 randomizes per note for humanization (low bound ≥1; v0-N is an error — v0 is the delete sentinel, not a range floor)
    • v0 deletes earlier notes at same pitch/time (deletes until disabled with non-zero v)
  • n<duration>: Note length as an absolute note value. Set it explicitly rather than relying on the n/4 default — and because it's stateful, re-set it whenever the intended length changes. It applies to notes after it — put the n change before the note it should affect (n/8 G3 4|2 A3, not G3 4|2 n/8 A3, which leaves G3 at the old length and overlaps A3). For drums, set n at the start and again for each drum/pitch (a hat's n/16 otherwise carries over to the next kick). REQUIRES denominator — n1, n2.5, n0.5 are invalid; write n/4, n5/8, n/8. n/12 = eighth triplet (3 in a quarter), n/6 = quarter triplet (3 in a half)
  • p<chance>: Probability from 0.0 to 1.0 (default: 1.0 = always). Opt-in — if any note uses probability, set it on every note (a stray p otherwise rides along)
  • Notes: C0-G8 with # or b for sharps/flats (C#3, Bb2; case-insensitive). C3 = middle C
  • Shortcut (stateful): omit any of v/n/p to reuse its last value — they don't reset per note, so re-state one whenever it should change. v/n/p and pitch persist until changed
  • Same-pitch overlap: two notes of the same pitch can't sound at once — if one's length runs into the next same-pitch note, Live truncates the earlier to end where the next starts. Both are kept (authored notes aren't dropped for overlapping); same pitch and start collapses to one
  • copying bars (MERGES - use v0 to clear unwanted notes):
    • @N= copies previous bar; @N=M copies bar M to N; @N-M=P copies bar P to range
    • @N-M=P-Q tiles bars P-Q across range; @clear clears copy buffer
    • Copies capture each note's v/n/p at the time it was written, not the current state
Editing Existing Notes (update-clip)

notes MERGES into an existing clip — a new note overwrites the existing note at the same pitch+start (restate n/8 G3 4|2 to shorten that G3); other notes are untouched. So don't rewrite the whole clip to change a few notes — restate just those. To delete, move, clear a region, or otherwise change notes already in the clip, use preTransforms (see Transforms) — to replace a region rather than edit in place, clear it first (preTransforms: "1|1-2|1: delete") or the notes you didn't restate stay behind.

Examples

C#3 F3 G#3 1|1 // chord at bar 1 beat 1
C3 E3 G3 1|1,2,3,4 // same chord on every beat
C1 1|1,3 2|1,2,3 // same pitch across bars (1|1,3,2|1,2,3 also works — the bar| sticks)
n/16 C3 1|1.75 // 16th note at beat 1.75
n/12 C3 1|1 E3 1|1+n/12 G3 1|1+n/6 // eighth-triplet arp C-E-G on beat 1 (varying pitch → ±n offsets, not a repeat)
n/12 C3 1|1x3 // eighth-note triplets: 3 notes filling one quarter (step = duration)
n/16 Gb1 1|1x16 // 16 sixteenths = 4 quarters, a full bar in 4/4 (1|1x16@n/16 is the same)
[C3 E3 G3 C4] 1|1x4@n/4 // melodic line: C3,E3,G3,C4 on 4 quarters (pitch bracket steps the list, not 4× one pitch)
C3 D3 1|1 v0 C3 1|1 // delete earlier C3 (D3 remains)
C3 D3 1|1 @2=1 v0 D3 2|1 // bar copy then delete D3 from bar 2
v90-110 n/4 C1 1|1,3 n/8 D1 1|2,4 // humanized drums — re-set n per lane
n/16 Gb1 1|1,1.5,2,2.5 n/4 C1 1|1 // re-set n/4 for kick, else hat's n/16 leaks onto it
p0.5 n/4 C1 1|1,2,3,4 // 50% chance each kick plays
Bar Copying

Complete bars before copying. Use beat lists for irregular patterns.

C1 1|1,3 D1 1|2,4 // bar 1
@2-3=1            // bar 1 -> 2,3
C1 4|1,3.5 D1 4|4 // bar 4
@5-7=1            // bar 1 -> 5,6,7
@8=4              // bar 4 -> 8
Repeats with Variations

Copy foundation to all bars (including variation bars), then modify:

C1 1|1,3 D1 1|2,4       // bar 1 foundation
Gb1 1|1.5,2.5,3.5,4.5
@2-16=1                 // copy to ALL bars, not just 2-8
v0 Gb1 9|4.5 v100       // remove hat from bar 9
C1 9|3.5                // add extra kick to bar 9
v0 C1 13|3 v100 D1 13|3 // replace kick with snare in bar 13

Audio Clips

ppal-read-clip sample include: sampleFile, gainDb (dB, 0=unity), pitchShift (semitones). warp include: sampleLength, sampleRate, warping, warpMode. Audio params ignored when updating MIDI clips. What Producer Pal can do with audio: set gain/pitch/warp settings, change clip length, place and arrange audio clips in the Arrangement, and load/manage samples on Simpler instruments (including Drum Rack pads). What it can't (yet): listen to, analyze, or transcribe audio content (no detecting notes/key/tempo from a waveform, no audio→MIDI), and no synthesizing/generating audio from scratch. Those are common requests, under consideration for a future release — say so plainly when asked rather than implying it can.

Transforms

Add transforms parameter to create-clip, update-clip, or duplicate.

Shape: a single string, broadcast across every clip/copy. Multiple expressions: newline-separated. Per-clip variation: clip.index arithmetic or clipseq() inside the string (below). Structurally-distinct edits per clip → separate tool calls.

Syntax: [selector:] parameter operator expression (one per line)

  • Selector: pitch and/or time filter, optionally a where(...) value test, followed by : - e.g., C3:, 1|1-2|4:, C3 1|1-2|4:, 1|1-2|4 C3:, where(note.velocity < 40):. Per-line: every selector (pitch, time, where) applies only to its own line — never carried to or inherited from neighbors; a line with no selector hits all notes. Repeat the selector to scope several lines
  • Pitch filter: C3 (single) or C3-C5 (range) - omit for all pitches
  • Time filter: 1|1-2|4 (bar|beat range, ends inclusive, matches note start time); bounds use the same beat dialect as positions (decimal or ±n offset, e.g. 1|1+n/12-2|1)
    • Single point: a bare bar|beat with no - (4|3.5:) targets only the note starting exactly there — e.g. Gb1 4|3.5: ratchet(4) rolls just that note
    • Whole bars: 3|* = all of bar 3, 1|*-3|* = bars 1-3 — half-open, so exactly those bars with no spill onto the next downbeat. Prefer this for "measure N"; 3|1-4|1 would also match a note on 4|1
    • Exclusive end: append -< to make only the end bound exclusive — 3|1-<4|1 = up to but not including 4|1 (for sub-bar half-open spans)
  • Value filter where(...): keep only notes whose properties satisfy a boolean test — where(note.velocity < 40): delete deletes quiet notes, where(note.velocity > 100): velocity += 20 accents loud ones, where(note.probability < .5): delete thins. Build it from comparisons (> >= < <= == !=), booleans (&& || !), parens, arithmetic, and functions over note.velocity/deviation/duration/probability/pitch/start (note.duration/note.start in musical beats; RHS may be a number, note name, or n/8). Functions work too — where(abs(note.start - 4) < 1): velocity += 20 (near beat 4, either side), where(min(note.velocity, note.deviation) > 80): .... AND-combines with a pitch/time selector: C3-C5 where(note.velocity > 80): velocity += 20. Comparisons tolerate sub-beat float drift, so ==/!= are safe even on float props (note.start == n/8 matches a note that names that beat); still prefer </> for ranges. Note properties only (no note.index/count/next); all functions except legato/seq (they need the selection); not on note-count ops
  • MIDI parameters: velocity (<=0 deletes note, else capped at 127), pitch (0-127), timing (musical beats), duration (musical beats; <=0 deletes note), probability (0-1), deviation (-127 to 127)
  • Audio parameters: gain (-70 to 24 dB), pitchShift (-48 to 48 semitones)
  • Operators: +=, -= (add/subtract), *=, /= (scale current value), = (set)
  • Shorthand (clears/simple sets): a single bar|beat-style token instead of param = valuedelete (or v0) delete a note · vN/v±N/vA-B velocity (range = humanized random, same as notes) · pN/p±N probability · n/4/Nbar/1bar+n/4 duration · C4 remap pitch (one per line; a selector still applies, e.g. C1: delete). delete is a transforms/preTransforms alias only — bar|beat notes strings still use v0. Preferred for clearing/deleting; use the full param op expr form for computed changes (+=, *=, waveforms, ramps). Note vA-B is the one shorthand with no param = ... longhand — it sets velocity AND velocity_deviation together, so write it as the shorthand (velocity = vA-B errors)
  • Expression: arithmetic (+, -, *, /, %) with numbers, waveforms, math functions, current values, and durations: n<dur> note values (e.g. n/4 = a quarter in any meter) and Nbar meter-aware bars (e.g. 1bar, 1bar+n/4) — same grammar as bar|beat and length fields. Both evaluate to musical beats and compose in any math expression (so in a non-time param like velocity a bare 1bar resolves to its beat count — e.g. 4 in 4/4 — rarely what you want there)
  • Math functions: round(x), floor(x), ceil(x), abs(x), clamp(val,min,max), wrap(val,min,max) (wrap to inclusive range), reflect(val,min,max) (bounce within inclusive range), min(a,b,...), max(a,b,...), pow(base,exp), snap(pitch) (snap to Live Set scale; no-op if no scale), step(pitch, offset) (move by offset scale steps; even distribution for waveforms), legato([tolerance]) (set duration to reach next note's start time; optional tolerance in musical beats groups nearby starts as chords, e.g. legato(0.1) after humanizing)
  • Timing functions: swing(amount [, grid] [, raw]) (auto-quantizes to grid then applies swing; amount=delay in musical beats — meter-relative, so these hints assume a quarter-note beat and scale up in x/8: 0.02=subtle, 0.05=medium, 0.1=heavy; grid: default = half the meter's beat (8th-note swing in x/4, 16th in x/8); override e.g. n/16; raw: skip auto-quantize), quant(grid) (snap to nearest grid point). Grid ref for both: n/4=quarter, n/8=8th, n/16=16th, n/12=triplet. swing()/quant() return an absolute position, so assign them with timing = (not +=). Relative nudges use +=/-= with a note value — timing += n/8 shifts every note an eighth later
  • Note-count operations (change how many notes exist — write on their own line, NOT as a value: velocity = ratchet(2) errors): ratchet(N) divides each matched note into N equal pieces (a roll); ratchet(n/16) instead cuts on the absolute 16th-note grid (pieces align to bar positions, partial slivers at the ends); repeat(offset, copies) echoes each matched note forward by offset (a note value like n/8 or Nbar); copies defaults to 1, so repeat(n/8) adds one echo an 8th later and repeat(n/8, 3) adds three (it does NOT resize the clip — copies past the end stay hidden until you grow length; to double a loop AND lengthen the clip, use update-clip's duplicateLoop instead); split(2|1, 2|3) cuts at explicit, possibly unequal clip bar|beat positions (each position cuts whichever matched note spans it; add a trailing syncsplit(6|1, sync) — to read positions on the arrangement timeline instead, ignored with a warning on session clips); merge() spans all same-pitch matched notes into one sustained note (optional gap tolerance: merge(0) glues only touching/overlapping notes, merge(n/8) glues notes within an 8th-note gap). A selector scopes them (C1: ratchet(4), 2|*: merge()); a transform after a note op sees the rebuilt notes (so note.index re-derives). MIDI only

Waveforms (-1.0 to 1.0, per note position; once for audio):

  • cos(period), square(period) - start at peak (1.0); sin(period), tri(period), saw(period) - start at zero, rise to peak
    • All accept optional phase offset — a 0..1 cycle fraction, not a time value: cos(n/4, 0.25) (quarter-cycle shift). square adds pulse width (3rd arg, also a 0..1 fraction): square(n/4, 0, 0.75) (phase=0, 75% duty cycle)
  • rand([min], [max]) - random value (no args: -1 to 1, one arg: 0 to max, two: min to max)
  • seq(a, b, ...) - cycle by the property's natural axis: note.index for per-note params, or clip.index for clip-granular params (gain, pitchShift) that have no note axis (same result as clipseq() there)
  • clipseq(a, b, ...) - cycle by clip.index across the batch of clips — forces the clip axis even on per-note params (enumerated per-clip variation, e.g. pitch += clipseq(0, 5, 7))
  • choose(a, b, ...) - random selection from arguments
  • ramp(start, end) - linear interpolation; reaches end value at time range end (or clip end)
  • curve(start, end, exp) - exponential (exp>1: slow start, exp<1: fast start); reaches end value at time range end
  • For ramp/curve, end the time filter on the last note's beat position so it reaches its end value. In 4/4: last 8th=N|4.5, last 16th=N|4.75
  • Waveform period is a note value: n/4 = quarter-note cycle, n/1 = whole-note cycle, n/2 = half-note cycle. For a meter-aware bar-length cycle use Nbar (e.g. cos(1bar), cos(4bar)). Same n fraction grammar as everywhere; bare numbers are beats
  • sync keyword (last arg on periodic waves) anchors phase to the arrangement timeline (continuous across clips) instead of clip start. Only meaningful on arrangement clips: a session clip has no arrangement position, so sync is ignored and the wave degrades to clip-relative (phase resets at clip start) with a warning — the modulation still applies. Without sync, phase is clip-relative everywhere (the default)

Variables: note.pitch, note.velocity, note.start, note.duration, note.probability, note.deviation, note.index (time-ordered), note.count (MIDI), next.pitch, next.velocity, next.start, next.duration (next distinct-start note; skips chords; warns on last note), audio.gain, audio.pitchShift (audio), clip.duration, clip.index (order of ids), clip.count, clip.position (arrangement only)

timing = swing(0.05)             // swing (auto-quantizes). Use swing() alone unless asked for a specific grid
timing = quant(n/8)              // snap to 8th-note grid
timing = quant(n/16)             // snap to 16th-note grid
timing += 0.05 * rand()          // humanize timing
timing += n/8                    // nudge every note an eighth note later (relative)
velocity += 20 * cos(n/2)        // cycle every half note (2 beats in 4/4)
velocity += 20 * cos(1bar, sync)  // bar-length cycle, continuous across clips
1|1-4|4.75: velocity = ramp(40, 127) // crescendo over 4 bars (16th grid)
C1-C2: velocity += 30            // accent bass notes
where(note.velocity < 40): delete // delete the quiet notes
where(note.velocity > 100): velocity += 20 // accent the loud ones (clamps at 127)
C3-C5 where(note.probability < .5): delete // thin low-probability notes in a pitch band
1|1-2|4: velocity = 100          // forte in bars 1-2
velocity = seq(100, 60, 80, 60)  // cycle accents per note (MIDI)
Gb1: pitch = seq(Gb1, Gb1, Gb1, Gb1, Ab1) // every 5th closed hat → open hat
pitch += clipseq(0, 5, 7)        // copy 0 unchanged, copy 1 +5, copy 2 +7 (per-clip)
gain = audio.gain - 6            // reduce audio clip by 6 dB
pitch = snap(note.pitch + 7) // transpose up fifth, snap to scale
pitch = step(note.pitch, sin(n/1) * 7) // oscillate ±7 scale steps smoothly
pitch = wrap(note.pitch + 5, C3, C5) // transpose up 5, wrap within C3-C5
velocity *= 0.5                  // halve all velocities
C1-C2: duration /= 2             // halve duration of bass notes
duration = n/8                   // every note → an eighth note (any meter)
duration += n/16                 // lengthen every note by a sixteenth
duration = legato()              // extend each note to reach the next
duration = legato(0.1)           // legato with tolerance (after humanizing timing)
ratchet(2)                       // split each note into two equal pieces (a roll)
ratchet(n/16)                    // cut each note on the 16th-note grid instead
C1: ratchet(4)                   // 4-stroke roll on the kick only
repeat(1bar)                     // echo every note one bar later (does not resize the clip)
repeat(n/8, 3)                   // three 8th-note echoes (original + 3 copies)
split(2|1, 2|3)                  // cut notes at explicit (unequal) clip positions
split(6|1, sync)                 // cut at an arrangement-timeline position
merge()                          // span same-pitch notes into sustained notes
merge(0)                         // ...but only where they touch or overlap

swing() auto-quantizes, so changing the amount is always safe without a separate quant(). Skip it with raw: swing(0.05, raw)

update-clip's quantizeGrid param uses Live's native grid enum (1/4,1/8,1/8T,1/16,1/16T,1/32) but also accepts the equivalent n/N note value (n/12=1/8T, n/24=1/16T, etc.); the mixed grids 1/8+1/8T/1/16+1/16T are enum-only.

+= compounds on repeated calls; = is idempotent. *=//= scale the current value (timing *= scales absolute note position). Use update-clip with only transforms to modify existing notes. Transforms modify notes in place — previous transforms are already baked in, so don't re-apply earlier ones. MIDI params ignored for audio clips, vice versa. Across a batch (update-clip ids / duplicate copies / create-clip multiple slots or arrangement positions), clip.index/clip.count span the full batch — drive per-clip variation with clip.index arithmetic (pitch += clip.index * 12) or clipseq(); see Shape above.

preTransforms (editing notes already in the clip)

preTransforms is the way to delete or change notes already in the clip. Pipeline: preTransforms → notes (merge) → transforms. It runs on the existing notes BEFORE any new notes merge — clear a whole bar (3|*: delete), a region (1|1-2|1: delete), a lane (C1: delete), everything (delete), or remap (C1: C4); the delete shorthand (alias v0) is preferred for clearing (velocity = 0 is the longhand equivalent). Works with or without notes; ignored on audio clips. Same syntax as transforms. transforms then mutates the merged result — also the efficient way to thin density: generate with repeats/bar-copies in notes, then prune with a selector instead of scattering deletes. (A v0 at an existing note's start also deletes it, but prefer preTransforms; reserve inline v0 for notes built in the same notes string.)

Finding Library Content

Use ppal-library to search Live's browser library and the user's configured sample folder.

  • Defaults to audio samples (the only kind loadable into clips/Simpler today). Other kind values are discovery-only.
  • query is a name substring; use * as a multi-character wildcard (e.g., kick*acoustic).
  • tags is comma-separated; results must match ALL listed tags. Use action: "listTags" to discover available tags, or action: "listCategories" to browse Live's category taxonomy (Sounds, Drums, Genres, …) and category: "Drums" to list a category's tags.
  • type filters by playback type: loop (loops), oneshot (one-shots, e.g. a kick), impulse-response (convolution IRs). Each result also reports type, so you can tell a one-shot kick from a drum loop — prefer oneshot for hits and loop for grooves.
  • kind: "midi" covers ALL MIDI content — both .mid files and MIDI Live clips (.alc) — so it's the right kind for melody/chord ideas. kind: "live-clip" returns every .alc (MIDI and audio); .alc results carry subtype (midi/audio) to disambiguate.
  • source: filter where the file lives. sampleFolder is the user-configured sample folder on disk (bypasses Live's DB); user, pack, builtin, cloud, plugin query Live's DB.
  • inFolder restricts a search to immediate children of one absolute folder path (composes with the other filters).
  • verifyPaths: true stats each result and adds pathExists so you can skip files moved/deleted since Live last indexed (off by default; adds one filesystem check per result).
  • action: "searchBatch" runs many filtered searches in one call. Pass queries as an array of objects each carrying the same filters as a single search plus an optional label; results come back grouped per query (capped at 20).
  • action: "listPlugins" enumerates installed VST/AU/etc. from Live's plugin DB. Filter with query (name substring), vendor, format (VST/VST3/AU), deviceKind (instrument / audiofxmidifx has no plugin equivalent), or subcategory.
  • action: "findSimilar" ranks samples by audio similarity to a seed sample (similarTo: an absolute path, e.g. from a prior result); each result carries a similarity score (-1 to 1, ~1 = very similar). Combine with the search filters to constrain candidates (e.g. similarTo a kick + tags: "Kick" for "more kicks like this"). action: "findDuplicates" groups library samples with identical audio (re-shipped duplicates), scoped by the same filters.
  • Items from the user's sample folder appear before Live's library items in results.
  • Each result includes folder (its immediate parent folder name). Use it to sanity-check tag hits: Live's tags are noisy, so a Kick-tagged file under an IR Library folder is probably a reverb impulse, not a drum.
  • Pass an absolute path from a result to ppal-create-clip / ppal-update-clip (audio clips) or ppal-create-device / ppal-update-device (Simpler sample).

Devices & Instruments

Device Paths

Slash-separated segments: t=track, rt=return, mt=master, d=device, c=chain, rc=return chain, p=drum pad

  • t0/d0 = first device on first track
  • rt0/d0 = first device on Return A
  • mt/d0 = first device on master track
  • t0/d0/c0/d0 = first device in rack's first chain
  • t0/d0/rc0/d0 = first device in rack's return chain
  • t0/d0/pC1/d0 = first device in Drum Rack's C1 pad

Chains are auto-created when referenced (e.g., c0 on an empty rack creates a chain). Up to 16 chains.

Simpler & Drum Racks

Simpler sample: Load a sample with params: [{name: "sample", value: "<absolute file path>"}] on ppal-create-device or ppal-update-device; set its level with {name: "gainDb", value: <dB>} (0 = unity). sample is always a params entry — there is no top-level sample argument. Read-device: include: ["sample"] returns just the sample file path as a flat top-level sample field (ideal for scanning every pad's sample in a drum rack); include: ["params"] returns the full set including sample, gainDb, and multiSampleMode. Writes are skipped with a warning on non-Simpler devices and on Simpler in multi-sample mode.

Build a Drum Rack (one call): Create the rack and load every pad's sample in a single ppal-create-device: deviceName="Drum Rack" path="t0" params=[{name:"pC1/d0/sample", value:"<abs path>"}, {name:"pC#1/d0/sample", value:"<abs path>"}, ...]. A param name containing / is a path relative to the rack: the pad-note segment addresses the pad (pC1, pF#1), d0 its first device, and the last segment is the param. Setting a pad's sample is a pad property — the pad's chain and a Simpler to hold the sample auto-create as needed. Add {name:"pC1/d0/gainDb", value:<dB>} (listed after the sample) to set a pad's level. Standard layout: 16 pads chromatically from C1 up to D#2/Eb2. Get sample paths from ppal-library; to match an existing kit's pad notes, read the track with drum-map first. The same path-prefixed params work on ppal-update-device to set/replace samples on an existing rack.

Pad sample-write policy (applied per pad; a skip-and-warn never tears down the rack): empty pad → create Simpler + load; pad with a Simpler → replace its sample; Simpler in multi-sample mode → skip+warn; pad with a DrumSampler → replaced with a Simpler + a notice (DrumSampler's sample is not controllable via the Live API); any other device → skip+warn. To swap a pad that skip-warned, delete its device first then set the sample: ppal-delete type="device" path="t0/d0/pC1/d0" clears the device inside the pad (chain stays); to remove the whole pad instead use ppal-delete type="drum-pad" path="t0/d0/pC1". ppal-delete accepts comma-separated paths to clear several pads at once.

Specialized Device Controls

Some native devices expose class-level controls beyond their DeviceParameters, through two surfaces: pseudo-params (set via params {name, value} entries, read back in parameters) and actions (function-call strings on update-device). Discover a device's surface at runtime rather than guessing values: read-device include: ["params"] lists its pseudo-params, include: ["actions"] lists action signatures, and include: ["options"] returns the valid values for each pseudo-param (paramOptions) plus dynamic catalogs (wavetables, IR files, sidechain sources) and Wavetable mod routes/sources. Invalid enum values warn-and-skip and list the valid options. The bullets below give each device's pseudo-params and non-obvious behavior — read options for accepted values.

Instruments:

  • Drift mod matrix. Fixed-target source slots filterMod1Source filterMod2Source lfoSource pitchMod1Source pitchMod2Source shapeSource; three free slots pair mod1Source/mod2Source/mod3Source with mod1Target/mod2Target/mod3Target (target None disables the slot). For each active free slot also set its matching amount DeviceParameter (e.g. Mod Matrix Amt 1). Plus voiceMode (Poly/Mono/Stereo/Unison), voiceCount, pitchBendRange.
  • Wavetable filterRouting, monoPoly, polyVoices, unisonMode, unisonVoiceCount, osc1Engine/osc2Engine. For osc1Category/osc2Category + osc1Wavetable/osc2Wavetable, set category first (options oscWavetableCategories, then osc1Wavetables/osc2Wavetables list the selected category's tables). Mod matrix via actions; options returns current routes (modulations), modulatableParameters, and modulationSources.
  • Meld monoPoly, polyVoices, unisonVoices.
  • Simpler sample (file path), gainDb (sample level, 0 = unity), playbackMode (classic/one-shot/slicing), slicingPlaybackMode, retrigger, voices; read-only multiSampleMode, estimatedPlaybackLength. Sample-editing actions operate on the active region — set the S Start/S Length DeviceParameters first to target a sub-range.

Audio effects:

  • Compressor sidechain: sidechainSourceTrackId (a trackId, or null for No Input), then sidechainChannel — set the source first, as the valid channels vary by source. options lists sidechainSourceTrackIds and the current source's sidechainChannels.
  • EQ Eight globalMode (stereo / L/R / M/S), oversample. In L/R the A bands process Left and B bands Right; in M/S, A = Mid and B = Side. Set globalMode, then write the A-/B-suffix band DeviceParameters (e.g. 5 Frequency B).
  • Hybrid Reverb irCategory, irFile (set category first; options irCategoryList, then irFileList lists the selected category's files), irAttackTime, irDecayTime, irSizeFactor, irTimeShapingOn.
  • Roar routingMode, envListen.
  • Spectral Resonator midiGate, monoPoly, pitchBendRange, modMode, pitchMode, polyphony.
VST/AU Plugins

Producer Pal can open or close a plug-in's editor window (openPluginWindow on ppal-select) but cannot control anything inside a VST/AU plug-in directly — its internal parameters aren't exposed to the Live API. To make a plug-in's parameters controllable, the user maps them onto the Live plug-in device in Live's Configure mode (expand the device, click "Configure", then click the controls in the plug-in to expose); Producer Pal can then read and set those mapped parameters like any other device parameter. You cannot do the mapping for the user — explain the steps and point them to the Configure mode manual. Limits: up to 128 parameters can be mapped (so pick the most important ones), and not every plug-in parameter is mappable.

Arrangement

Moving Clips

arrangementStart moves arrangement clips; toSlot (trackIndex/sceneIndex, both 0-based — scene 1 = index 0) moves session clips. Moving clips changes their IDs - re-read to get new IDs. arrangementLength sets arrangement playback region. split divides arrangement clips at bar|beat positions measured from the clip's own start (1|1 = clip start, NOT song position).

Take Lanes (Arrangement Variations)

Stack alternate takes of an arrangement clip at the same position; only the active take plays (the user auditions/comps in Live's UI).

  • takeLane on create-clip + duplicate (arrangement only; duplicate is MIDI-only): omit/0 = main lane; 1+ = that lane (auto-created up to it); "new" = append a fresh lane. takeLaneName names a lane this call creates.
  • Variation workflow: a few duplicate calls with takeLane: "new" + transforms to vary each copy. read-track arrangement-clips include lists takeLanes — each entry carries takeLane (1-based, matching the write param) and its name, so you can round-trip a read back to a write directly.
  • 8 lanes/track max; creating over an existing clip replaces it (like the main lane). One-way: Producer Pal can't delete or comp take lanes — that's done in Live (expand the track's take-lane arrow to see them).
  • Take-lane clips are append-only: update-clip (split, arrangementStart, arrangementLength) and ppal-delete warn+skip on them. Main→take duplicate recreates the clip from notes and drops envelope automation; take→main promote isn't supported. For any of these, ask the user to do it in Live's UI.

Working with Ableton Live

Views and Playback:

  • Session View: Jam, try ideas, build scenes
    • Use auto:"play-scene" when generating clips; warn user about clip restarts
  • Arrangement View: Structure songs on a timeline
    • Session clips override Arrangement; use "play-arrangement" for arrangement playback

Creating Music:

  • For drum tracks, read the track with drum-map include for correct pitches (don't assume General MIDI); set n per drum/pitch and space repeated hits with 1|1xN repeats, not hand-listed beats (see Time & Note Values)
  • Use velocity dynamics (pp=40, p=60, mf=80, f=100, ff=120) for expression
  • Keep harmonic rhythm in sync across tracks

Layering: To layer tracks on one instrument, duplicate with routeToSource=true. New track controls the same instrument.

Locators: Use ppal-update-live-set to create/rename/delete locators at bar|beat positions. Use locator names with ppal-playback to start or loop from named positions.

Getting Help

When something is outside Producer Pal's reach — a Live feature it can't drive (automation, comping take lanes, mapping plug-in/macro params), a known limitation, or just "how do I do X in Live" — don't dead-end the user. Explain the manual step and link the right resource.

Basic Skills (small model mode)

MIDI Notation

Pitches: C0-G8, # or b for sharps/flats (C#3, Bb2). C3 = middle C. Format: v<vel> n<dur> pitch(es) bar|beat — always state v and n explicitly (don't rely on defaults); set them before the pitches and they persist until you change them.

  • v: velocity 0-127 (louder = higher)
  • n: duration, and it REQUIRES a denominator: n/4 quarter, n/8 eighth, n/16 sixteenth, n/2 half, n/1 whole, n/12 eighth-triplet. Bare numbers are invalid.
  • bar|beat positions are 1-indexed and read left-to-right: 4|2 = bar 4 beat 2. One note per bar → step the LEFT number (1|1 2|1 3|1 4|1); move within a bar → step the right (1|1 1|2 1|3 1|4). A decimal lands inside a beat: 1|1.5 = the "&".

Generate notes

Melody (a quarter note per beat):

v100 n/4 C3 1|1 D3 1|2 E3 1|3 F#3 1|4
G3 2|1 A3 2|2 G#3 2|3 E3 2|4

Chords (multiple pitches share one position; n/1 = a whole bar):

v100 n/1 C3 E3 G3 1|1  D3 F3 A3 2|1

Drums (commas list beats for one pitch; re-set n per lane so it doesn't carry over):

v100 n/8 C1 1|1,3          # kick
v100 D1 1|2,4              # snare
v80 n/16 Gb1 1|1.5,2.5,3.5,4.5   # hats (softer, on the offbeats)

Add notes to an existing clip (update-clip)

notes MERGES into the clip: a note at the same pitch+start overwrites that note; every other note stays. So to add, just pass the new notes — don't resend the whole clip.

Delete / clear notes (update-clip preTransforms)

preTransforms clears or edits notes already in the clip, before any new notes in the same call:

  • v0 — delete all notes
  • [range]: v0 — delete notes in a range
  • ranges: C1 (one pitch) · C1-C5 (pitch range) · 3|* (all of bar 3) · 1|1-2|1 (explicit span, end inclusive)

Replace bar 1's snare, keep the rest: preTransforms: "D1 1|*: v0" with notes: "v100 n/8 D1 1|2,4"

Rules

  • Set clip length explicitly: 4bar, 1bar, n/4.
  • Read the set/track/clip to get IDs, indices, scale, and drum map — don't ask the user for what you can look up, and never guess a track.
  • If a tool call errors, read the message, fix the arguments, retry — don't claim it's unsupported.
  • Producer Pal can't analyze or generate audio (no audio→MIDI, key/tempo detection). Say so if asked. It can still set gain/pitch/warp, change clip length, arrange audio, and load samples on Simpler/Drum Rack pads.

Released under the GPL-3.0 License.