Tool Reference
Every Producer Pal tool and its parameters. For what Producer Pal can do in plain terms, start with Features.
The AI picks these tools and fills in the parameters itself; you don't call them by hand. Read this when you want to know exactly what a tool accepts, or when you're driving Producer Pal from the REST API or the Agent Skill.
About the example output
Every tool shows one example call and what it returns. They all run against the same made-up Live Set (three tracks: Drums, Bass, Vocals, plus one return and two scenes), so the names, IDs, colors, and file paths are invented. IDs are opaque in real Live Sets too: read one from a tool result, don't guess it.
The examples are pretty-printed here. Producer Pal sends a more compact form over the wire by default; ?format=json on the REST API gives you this shape.
Core Tools
Connect (ppal-connect)
- Summarizes the state of the current Live Set
- Returns a skill set and context that teach 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.
- Call it first when a model is driving Producer Pal. That's how the AI learns the notation and conventions. A plain REST script can skip it.
(no parameters)
Example output
Called with {}:
{
"connected": true,
"producerPalVersion": "2.5.0",
"abletonLiveVersion": "12.4.1",
"liveSet": {
"name": "Example Set",
"tempo": 110,
"timeSignature": "4/4",
"sceneCount": 2,
"regularTrackCount": 3,
"returnTrackCount": 1,
"isPlaying": true,
"scale": "F Minor",
"scalePitches": "F,G,Ab,Bb,C,Db,Eb"
}
}The response carries these as separate text blocks after the JSON, in this order — ppal-connect does not return them as fields on the result. What goes in them is up to you: see Context & Memory and Customizing Skills.
remoteScript: not installed. It adds clip automation, loading plug-ins, Max for Live devices and presets, audio-to-MIDI conversion, and undo/redo with one undo step per tool call. To install it, call ppal-manage action "install-remote-script", then tell the user to restart Live, then choose Producer Pal as a Control Surface in Settings → Tempo & MIDI, with Input and Output left as None.# Producer Pal Skills
## Positions & Meter
… 401 more linesProject context (this Live Set):
Downtempo sketch in F minor. Keep the drums sparse.Global context (all projects):
I write downtempo and lo-fi house. Keep arrangements under 3 minutes.Memory index. Read an entry before work it covers; when the user changes a fact an entry covers, rewrite that entry right away. Load a body with ppal-context (action:"read", scope:"memory", name:"<name>"):
- `prefers-hardware-drums` — Records drums on hardware, wants MIDI kept out of the kick busReport the connection status and Live Set overview to the user, then wait for their instructions.Context (ppal-context)
- Read and write the three context layers: project context (notes about this Live Set), global context (preferences that apply to every project), and memory (facts AI records about you as you work)
Parameters
| Parameter | Type | Description |
|---|---|---|
action | "read" |"write" |"delete" 🐘 | read (default): project/global → the document; memory → the entry named name, or the whole index if no name. write: replace the document, or create/update the memory entry name. delete: remove the memory entry name. |
scope | "project" |"global" |"memory" 🐘 | project (default): facts about THIS Live Set (genre, song structure), always in its context. global: who the user is across ALL projects (style, preferences, high-level goals), always in context. memory: durable facts and rules that matter only in CERTAIN situations, loaded on demand by name. |
content | string | Text to write — project/global: the whole document; memory: the entry body (one fact). Max 10000 chars. |
name 🐘 | string | Memory entry name (read/write/delete on scope:memory only), one entry per call. Reuse a name to update, not duplicate. |
description 🐘 | string | Memory entry's one-line recall hook for the index — what's inside and when it's relevant. Required on a memory write. |
force | boolean | Only when a write was refused for dropping the whole document: true replaces it anyway. |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"action":"read"}:
{
"content": "Downtempo sketch in F minor. Keep the drums sparse."
}Manage (ppal-manage)
- Install the Producer Pal remote script into your User Library, without opening the Chat UI. Restart Live afterwards.
- Add the Producer Pal device to the open Live Set, on a new MIDI track, and install it in your User Library first if needed. Works while Producer Pal isn't running yet, through
npx producer-palor the Claude Desktop extension. Needs the remote script. - Update the Producer Pal device in the open Live Set to the version your
npx producer-palor Claude Desktop extension ships. It replaces the device in place and keeps your project context. Your AI offers this when the device is older. Needs the remote script. - Undo and redo in Live's own history, one step or several at a time. One Producer Pal tool call that changed the Live Set is one step. It never removes Producer Pal itself. The history also holds your own edits in Live, so an undo can revert something you did. Needs the remote script.
- Not available in small model mode.
Parameters
| Parameter | Type | Description |
|---|---|---|
action | "install-remote-script" |"add-producer-pal" |"update-producer-pal" |"undo" |"redo"(required) | install-remote-script: put the remote script in the User Library (adds clip automation, plug-in/preset loading, audio-to-MIDI and undo/redo); the user must then restart Live. add-producer-pal: put the Producer Pal device on a new MIDI track in the open Live Set, while Producer Pal isn't running yet; needs the remote script. Ask the user first: it changes their Set. update-producer-pal: replace the running Producer Pal device with the newer one this connector ships, in place; only works through that connector (npx or Claude Desktop); needs the remote script. Ask the user first. undo, redo: step back or forward; needs the remote script |
steps | integer | undo, redo only: how many steps, default 1, max 50. Stops where history ends. |
userLibrary | string | install-remote-script, add-producer-pal, update-producer-pal only: absolute path to Live's User Library, for when it can't be found automatically. Ask the user (Live: Settings → Library → Location of User Library). |
Example output
Called with {"action":"install-remote-script"}:
{
"version": "2.5.0",
"path": "/Users/example/Music/Ableton/User Library/Remote Scripts/Producer_Pal",
"nextSteps": "Tell the user to finish in Live: restart Live, then, on first install, choose \"Producer Pal\" as a Control Surface in Settings → Tempo & MIDI, with Input and Output left as None. It takes one free slot and no MIDI, so their other controllers keep working."
}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
- Playback always follows the Arrangement (no per-track override)
- Stop all clips or specific clips
Parameters
| Parameter | Type | Description |
|---|---|---|
action | "play-arrangement" |"update-arrangement" |"play-scene" |"play-session-clips" |"stop-session-clips" |"stop-all-session-clips" |"stop"(required) | play-arrangement: from startTime, or from wherever it already is update-arrangement: set startTime and/or loop, without playing play-scene: all clips in scene play-session-clips: by id(s) or path(s); a group track's slot fires the tracks inside it stop-session-clips: by id(s) or path(s); stops each slot's whole track (a group track: all inside it) (both answer with clip: {id, path} per target, in order; {id|path, ok:false, detail} for one not reached) stop-all-session-clips: all stop: session and arrangement; takes startTime to park the next play |
startTime | string | where arrangement playback starts, and restarts from if it's already playing. Stays put until something changes it: bar|beat in song meter, or loc:<locator name or id> (e.g. '5|1' or 'loc:Verse') |
loop | boolean | arrangement loop? |
loopStart | string | bar|beat (song meter) or loc:<locator>; turns the loop on |
loopEnd | string | bar|beat (song meter) or loc:<locator>; turns the loop on |
id | string | clip id(s), comma-separated; for play-scene, a scene id (or a clip id in that scene) |
path | string | clip slot(s) 't<track>/s<scene>', both 0-based, comma-separated (e.g., 't0/s1' or 't0/s1,t2/s3'); for play-scene, a scene 's<scene>' (e.g., 's3') or any position in it |
Example output
Called with {"action":"play-scene","path":"s0"}:
{
"playing": true,
"scene": {
"id": "201",
"path": "s0"
}
}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, plug-in preset folders, or your sample folder). The other files in plug-in preset folders (
Audio/Presets), such as sample libraries, are hidden by Live's browser and left out unless you ask for them; plug-in presets there stay listed under 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, which surfaces what you actually use most),mod-date, orname - Enumerate available tags with
action: "list-tags"so the AI can discover the tag vocabulary on your machine, or browse Live's category taxonomy (Sounds, Drums, Genres, …) withaction: "list-categories" - Run many filtered searches in one call by passing
searches(an array of query objects, each with its own filters); results grouped per query, so the AI can assemble a whole drum kit in one round trip - List the VST/VST3/AU plug-ins Live knows about with
action: "list-plugins"(filter by query, vendor, format, device kind, or subcategory) - Rank samples by audio similarity to a seed sample with
action: "find-similar"(Live's own similarity index, not Producer Pal listening), or group library samples with identical audio (re-shipped duplicates) withaction: "find-duplicates". Both can be narrowed with the search filters
Parameters
| Parameter | Type | Description |
|---|---|---|
action | "search" |"list-tags" |"list-categories" 🐘 |"list-plugins" 🐘 |"find-similar" 🐘 |"find-duplicates" 🐘 | search: filter library items (default) | list-tags: available tags | list-categories: Live's category taxonomy (Sounds, Drums, Genres, …); pass category to drill into its tags | list-plugins: installed VST/VST3/AU plugins (filter with query, vendor, format, deviceKind, subcategory) | find-similar: rank samples by audio similarity to similarTo | find-duplicates: group library samples with identical audio. find-similar and find-duplicates also take the search filters. |
query | string | name substring (search: supports * as a multi-character wildcard, e.g. kick*acoustic; list-plugins: plain case-insensitive substring) |
searches 🐘 | array | search only: run several filtered searches in one call (e.g. build a drum kit) instead of the top-level filters. Each entry takes the same filters as a single search, plus an optional label; results come back in order, grouped per query (max 20). One entry answers like a plain search, ungrouped |
tags | string | comma-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; audio is the only kind loadable into clips/Simpler). audio=samples | midi=.mid files plus MIDI .alc clips, so it covers all MIDI content | live-clip=all .alc clips (MIDI+audio; each result reports subtype) | preset=instrument/effect presets | device-group=.adg racks | m4l-device=.amxd | live-set=.als | plugin=VST/AU | image/video=media | folder=directory entries (distinct from source:sample-folder) |
type | "loop" |"oneshot" |"impulse-response" | playback type filter (search only): loop=loops | oneshot=one-shots (e.g. a kick) | impulse-response=reverb IRs, including ones other searches hide. Prefer oneshot for hits and loop for grooves. Also reported per result as type. |
category 🐘 | string | list-categories only: a top-level category name (from list-categories with no category) to drill into; returns its tag names, each usable as a tags filter |
similarTo 🐘 | string | find-similar only: absolute path of a seed sample (e.g. a path from a prior search) to rank other samples by audio similarity. Identical audio is listed once. Each result carries a distance (lower = more similar; no fixed scale). |
deviceKind 🐘 | "instrument" |"audiofx" |"midifx" | device classification filter (search + list-plugins; for list-plugins only instrument/audiofx apply) |
vendor 🐘 | string | vendor/manufacturer substring, case-insensitive (list-plugins only) |
format 🐘 | "VST" |"VST3" |"AU" | plugin binary format filter (list-plugins only) |
subcategory 🐘 | string | subcategory substring filter, case-insensitive (list-plugins only; matches any of a plugin's genre/role tags, e.g. reverb, delay, synth). Also reported per result as subcategories. |
source | "sample-folder" |"user" |"pack" |"builtin" |"cloud" |"plugin" |"preset-folder" | where the file lives (search only). sample-folder=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 and their presets | preset-folder=other files in plug-ins' preset folders (Audio/Presets), which Live's browser hides |
inFolder | string | absolute folder path; returns only immediate children of that folder (search only). Composes with other filters. Case-insensitive (ASCII). |
sort 🐘 | "use-count" |"mod-date" |"name" | sort order (search only); defaults to use-count desc |
verifyPaths 🐘 | boolean | search 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. |
limit | number | max results; defaults to 50 (search) or 200 (list-tags) |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"query":"kick","limit":2}:
{
"dbAvailable": true,
"items": [
{
"name": "Kick Deep 01.wav",
"path": "/Users/example/Music/Ableton/Factory Packs/Kick Deep 01.wav",
"kind": "sample",
"type": "oneshot",
"tags": [
"Kick",
"Drums"
],
"useCount": 12,
"source": "builtin",
"parentFolder": "One Shots"
},
{
"name": "Bass Sub.adg",
"path": "/Users/example/Music/Ableton/User Library/Bass Sub.adg",
"kind": "instrument-rack",
"tags": [
"Bass"
],
"useCount": 3,
"source": "user",
"parentFolder": "Instruments"
}
]
}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 (path, etc.)
- Update selection and return only relevant fields
- Select any object by ID (auto-detects track/scene/clip/device)
- Select by path: a clip slot (e.g.,
t0/s3), a track (t0), a return track (rt0), the main track (mt), a scene (s3), or a device (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
| Parameter | Type | Description |
|---|---|---|
id | string | select by ID (auto-detects track/scene/clip/device/chain/drum pad); one ID, not a list |
path | string | select by path, 0-based: 't0/s3' a clip slot, 't0' a track, 'rt0' a return track, 'mt' the main track, 's3' a scene, 't0/d1' a device, 't0/d0/c1' a rack chain, 't0/d0/pC1' a drum pad, 't0[5|1]' (or 't0/l0[5|1]') a spot on the arrangement timeline, which moves the arrangement start marker there and selects the clip covering it, if any. One path, not a list |
openPluginWindow 🐘 | boolean | open (true) or close (false) a plug-in's (VST/AU) floating editor window; targets the device given by id or path |
view | "session" |"arrangement" | main view |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"t0/s0"}:
{
"view": "session",
"selectedClip": {
"id": "301",
"path": "t0/s0"
}
}Action Tools
Delete (ppal-delete)
- Remove tracks, return tracks, scenes, clips, devices, drum pads, or rack chains
- Bulk delete multiple objects
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | id(s), comma-separated (must be same type) |
path | string | path(s) to delete, comma-separated for multiple: tracks ('t0', 'rt1'), scenes ('s0'), session clips ('t0/s1'), arrangement clips by a position they cover ('t0[5|1]'), devices ('t0/d1'), drum pads ('t1/d0/pC1'), one layer of a pad ('t1/d0/pC1/c1'). Deleting shifts every later sibling down, so a path in the result is the address from before the call. |
type | "track" |"scene" |"clip" |"device" |"drum-pad" |"chain"(required) | type of objects to delete; 'chain' removes one chain from a Drum Rack pad |
Example output
Called with {"id":"303","type":"clip"}:
{
"id": "303",
"deletedPath": "t2/s1"
}Duplicate (ppal-duplicate)
- Copy tracks, scenes, clips, devices, or drum pads
- Create multiple copies at once
- Copy clips anywhere in the Session, Arrangement, or from Session to Arrangement
- A clip slot past the last scene creates the scenes up to it, reported as
created - Position in the Arrangement by bar|beat or locator
- Auto-tile clips to fill longer arrangement durations
- A session clip's automation is written onto the track's lane over the copy's span, replacing what that parameter's lane held there (see Clip Automation)
- A clip slot past the last scene creates the scenes up to it, reported as
- Apply transforms to each duplicated clip (e.g. transpose copies, vary velocities) without a separate update step
- Stack variations on take lanes, or copy or promote a whole lane (see Take Lanes below)
- Copy devices to any track, return track, or rack chain
- Copy a drum pad or a rack chain with its settings and devices (see Drum pads and rack chains below)
- Route duplicated tracks to source instrument for MIDI layering
- With the remote script, effects and effect racks are copied in place
Note: Return tracks can't be duplicated. Devices on return and main tracks can be copied when the Producer Pal remote script is running.
Drum pads and rack chains
- Copy a whole drum pad to another pad in the same rack, bringing its chain trim, pan, sends, choke group, and devices. A device-only copy leaves the chain (and its trim) behind
- Copy a chain of any rack with
type: "chain", carrying its name, color, mute/solo, chain trim, and devices.toPathnames the destination rack and may cross racks of the same kind; omit it to append to the chain's own rack. Sends carry when the destination rack has a return chain of the same name. Macro mappings can't be reproduced through the Live API, so a rack that has them says so
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | id(s), comma-separated (type 'track' also takes a take lane's id, which needs a lane or track toPath) |
path | string | path(s) of the object(s) to duplicate, instead of or alongside id, comma-separated for multiple (e.g. 't0', 's1', 't0/s1', 't0[5|1]', 't0/d0', 't0/d0/pC1'; 't0/l0' names a take lane, and needs a lane or track toPath) |
type | "track" |"scene" |"clip" |"device" |"drum-pad" |"chain"(required) | type of object to duplicate |
name | string | name, or comma-separated one per copy |
color | string | #RRGGBB, or comma-separated one per copy |
count 🐘 | integer | copies per source, max 25 (tracks/scenes only; not with a list of destinations) |
withoutClips 🐘 | boolean | exclude clips? |
withoutDevices 🐘 | boolean | exclude devices? |
arrangementLength | string | clip/scene copies to the arrangement only. duration, e.g. '4bar' (see Skills), or comma-separated one per copy; song meter. Shorter than the source trims the copy; longer tiles copies to fill the span (many clips, not one) — for a single clip use ppal-update-clip with looping false and notes for the full length |
toPath | string | destination(s). Clips: 't2/s1' = a clip slot, third track and second scene (both count from 0, and scenes are created up to that index); 't2[5|1]' or 't2[loc:Chorus]' = that spot (bar|beat, or loc:<locator name or id>) on that track's arrangement, and '[5|1]' the same spot on the source clip's own track (an arrangement track must match the clip's MIDI/audio type; copying an arrangement clip leaves the track's automation behind, while a session clip's envelopes are written to the track's lane over the copy's span); 't2/l0' = its first take lane, and lanes are created up to that index; 't2' alone needs a position, and omitting toPath uses the source clip's own track. Devices: 't1/d+' appends, 't1/d0' inserts at 0. Chains: 't1/d0/c+' appends the copy to that rack (any rack of the same kind); omitting toPath appends to the chain's own rack. Scenes: '[5|1]' = that spot on the arrangement, across every track. Tracks: 't2/l0' (or 't2/l+') copies the source's arrangement clips onto that take lane, at the positions they already have. A track source copies its main lane, a 't2/l0' source that lane. A 't2/l0' source onto a bare 't2' promotes the lane's clips to the main lane, over the clips already there. Clips only, and the two tracks must match MIDI/audio type; name/color label the copies. A track copy needs no toPath otherwise. Drum pads: 't0/d0/pD1', required, and must be in the same rack as the source pad (id or path names the source). Comma-separated, one per copy; several sources need one each, except a bare '[5|1]' for clips |
routeToSource 🐘 | boolean | tracks only (errors otherwise): the copy gets no clips or devices of its own and plays the source track's instrument (for MIDI layering/polyrhythms) |
transforms 🐘 | string | transform expressions (broadcast across copies; clips only); newline-separated for multiple. Use clip.index / clipseq() for per-copy variation. Note-count operations (ratchet()/repeat()/split()/merge()) change how many notes exist |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"type":"clip","id":"301","toPath":"t0/s1"}:
{
"id": "603",
"path": "t0/s1"
}Live Set Tools
Read Live Set (ppal-read-live-set)
- Get complete Live project overview
- View all tracks and scenes at once, with a clip count per track (clip contents come from Read Track, Read Scene, and Read Clip)
- See tempo, time signature, and scale settings
- View arrangement locators with times and names
- Check what's playing and track states
- See whether the tempo has arrangement automation
Parameters
| Parameter | Type | Description |
|---|---|---|
include | array 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)
Example output
Called with {"include":["*"]}:
{
"name": "Example Set",
"tempo": 110,
"timeSignature": "4/4",
"scenes": [
{
"id": "201",
"path": "s0",
"name": "Intro",
"color": "#FF4C4C",
"clipCount": 1
},
{
"id": "202",
"path": "s1",
"name": "Verse",
"color": "#B87A35",
"tempo": 96,
"timeSignature": "6/8",
"clipCount": 2
}
],
"isPlaying": true,
"tracks": [
{
"id": "101",
"path": "t0",
"type": "midi",
"name": "Drums",
"color": "#FF4C4C",
"isArmed": true,
"instrument": "Drum Rack",
"gainDb": "0.0 dB",
"pan": 0,
"sends": [
{
"gainDb": "-inf dB",
"return": "A Reverb",
"returnId": "104"
}
],
"detail": "arrangement automation unknown while the track plays from Session",
"sessionClipCount": 1,
"arrangementClipCount": 0,
"deviceCount": 1,
"playingSlotIndex": 0,
"inputRoutingType": {
"name": "Ext. In",
"inputId": "17"
},
"inputRoutingChannel": {
"name": "In 1",
"inputId": "1"
},
"outputRoutingType": {
"name": "Track Out",
"outputId": "25"
},
"outputRoutingChannel": {
"name": "Master",
"outputId": "26"
},
"monitoringState": "auto"
},
{
"id": "102",
"path": "t1",
"type": "midi",
"name": "Bass",
"color": "#B87A35",
"instrument": "Analog",
"gainDb": "-3.0 dB",
"pan": -0.25,
"sends": [
{
"gainDb": "-12.0 dB",
"return": "A Reverb",
"returnId": "104"
}
],
"sessionClipCount": 1,
"arrangementClipCount": 1,
"takeLaneCount": 2,
"deviceCount": 2,
"inputRoutingType": {
"name": "Ext. In",
"inputId": "17"
},
"inputRoutingChannel": {
"name": "In 1",
"inputId": "1"
},
"outputRoutingType": {
"name": "Track Out",
"outputId": "25"
},
"outputRoutingChannel": {
"name": "Master",
"outputId": "26"
},
"monitoringState": "auto"
},
{
"id": "103",
"path": "t2",
"type": "audio",
"name": "Vocals",
"color": "#3DC300",
"gainDb": "-6.0 dB",
"pan": 0.5,
"sends": [
{
"gainDb": "-6.0 dB",
"return": "A Reverb",
"returnId": "104"
}
],
"sessionClipCount": 1,
"arrangementClipCount": 0,
"deviceCount": 0,
"state": "muted",
"inputRoutingType": {
"name": "Ext. In",
"inputId": "17"
},
"inputRoutingChannel": {
"name": "In 1",
"inputId": "1"
},
"outputRoutingType": {
"name": "Track Out",
"outputId": "25"
},
"outputRoutingChannel": {
"name": "Master",
"outputId": "26"
},
"monitoringState": "auto"
}
],
"returnTracks": [
{
"id": "104",
"path": "rt0",
"name": "A Reverb",
"color": "#7F7F7F",
"gainDb": "0.0 dB",
"pan": 0,
"deviceCount": 0,
"inputRoutingType": null,
"inputRoutingChannel": null,
"outputRoutingType": {
"name": "Track Out",
"outputId": "25"
},
"outputRoutingChannel": {
"name": "Master",
"outputId": "26"
}
}
],
"mainTrack": {
"id": "105",
"path": "mt",
"name": "Master",
"color": "#7F7F7F",
"gainDb": "0.0 dB",
"pan": 0,
"deviceCount": 0,
"inputRoutingType": null,
"inputRoutingChannel": null,
"outputRoutingType": null,
"outputRoutingChannel": null
},
"scale": "F Minor",
"scalePitches": "F,G,Ab,Bb,C,Db,Eb",
"locators": [
{
"id": "501",
"name": "Intro",
"time": "1|1",
"position": "loc:Intro"
},
{
"id": "502",
"name": "Verse",
"time": "9|1",
"position": "loc:Verse"
}
]
}Update Live Set (ppal-update-live-set)
- Change tempo, time signature, scale
- Create, rename, or delete arrangement locators, several per call
- Says when a tempo write overrides arrangement automation: Live then ignores that lane until you press Re-Enable Automation
Parameters
| Parameter | Type | Description |
|---|---|---|
tempo | number | BPM |
timeSignature | string | N/D (4/4) |
scale | string | "Root ScaleName" ("C Major", "F# Minor", "Bb Dorian"). Applies to selected clips and as the default for new clips. Empty string disables scale |
locatorOperation 🐘 | "create" |"delete" |"rename" | Locator operation |
locatorId 🐘 | string | locator id(s) from read-live-set (delete/rename), comma-separated |
locatorTime 🐘 | string | Bar|beat position(s), song meter; comma-separated for several. Required for create. Delete/rename: more locators, after any locatorId |
locatorName 🐘 | string | Create/rename: one name for all, or one per locator. Delete: each name is also a target, deleting every locator with that name |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"tempo":124,"scale":"F Minor"}:
{
"id": "1",
"scalePitches": "F,G,Ab,Bb,C,Db,Eb"
}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
| Parameter | Type | Description |
|---|---|---|
path | string | where it goes: 't+' appends, 't<index>' inserts there (t0 is the first track, so a user's "track 3" is t2), 'rt+' adds a return track. Comma-separated for several, one entry per track, in order (e.g. 't+,t+,t+' appends three, 't2,t2' inserts two at 2) |
name | string | name, or comma-separated one per track |
color | string | #RRGGBB, or comma-separated one per track |
type | "midi" |"audio" | type |
mute 🐘 | boolean | muted? |
solo 🐘 | boolean | soloed? |
arm 🐘 | boolean | record armed? |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"t3","name":"Keys"}:
{
"id": "601",
"path": "t3"
}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-clipsinclude), or read one lane on its own from a lane path (t2/l0) - See devices, routing options, and drum pad mappings
- See which instrument plays the track, including what's inside an Instrument Rack:
Instrument Rack (Operator, Wavetable) - Check track states (muted, soloed, armed)
- View mixer properties: gain, pan, panning mode, and send levels
- See which mixer fields have arrangement automation. Left out, with a reason, while the track plays from Session
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | track or take lane id(s), comma-separated |
path | string | track path(s) to read, comma-separated: 't<index>' (t0 is the first track, so a user's "track 3" is t2), 'rt0' for a return, 'mt' for the main track, 't0/l0' for one take lane |
include | array of:"session-clips" |"arrangement-clips" |"notes" |"timing" |"sample" |"warp" 🐘 |"devices" |"drum-map" |"routings" 🐘 |"available-routings" 🐘 |"mixer" |"color" |"*" 🐘 | session-clips, arrangement-clips = clip lists (arrangement-clips also lists take lanes). notes, timing, sample, warp = clip detail (use with clips). devices, routings, available-routings, mixer = track data. drum-map = the kit's actual pad pitches and names, plus drumRackPath (a pad path is <drumRackPath>/p<note>); read it before writing drums. color = track + clip color. "*" = all |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"t0","include":["*"]}:
{
"id": "101",
"path": "t0",
"type": "midi",
"name": "Drums",
"color": "#FF4C4C",
"isArmed": true,
"instrument": "Drum Rack",
"gainDb": "0.0 dB",
"pan": 0,
"sends": [
{
"gainDb": "-inf dB",
"return": "A Reverb",
"returnId": "104"
}
],
"detail": "arrangement automation unknown while the track plays from Session",
"sessionClips": [
{
"id": "301",
"name": "Kick + Hats",
"color": "#FF4C4C",
"playing": true,
"path": "t0/s0",
"timeSignature": "4/4",
"looping": true,
"start": "1|1",
"end": "2|1",
"length": "1bar",
"notes": "v110 n/16 C1 1|1 v100 C1 1|2,4\nv70 Gb1 1|1.5x4@n/4\nv105 D1 1|3"
}
],
"arrangementClips": [],
"devices": [
{
"id": "401",
"path": "t0/d0",
"type": "drum-rack",
"name": "Kit"
}
],
"drumMap": {
"C1": "Kick",
"D1": "Snare"
},
"drumRackPath": "t0/d0",
"playingSlotIndex": 0,
"inputRoutingType": {
"name": "Ext. In",
"inputId": "17"
},
"inputRoutingChannel": {
"name": "In 1",
"inputId": "1"
},
"outputRoutingType": {
"name": "Track Out",
"outputId": "25"
},
"outputRoutingChannel": {
"name": "Master",
"outputId": "26"
},
"monitoringState": "auto",
"availableInputRoutingTypes": [
{
"name": "Ext. In",
"inputId": "17"
}
],
"availableInputRoutingChannels": [
{
"name": "In 1",
"inputId": "1"
}
],
"availableOutputRoutingTypes": [
{
"name": "Track Out",
"outputId": "25"
}
],
"availableOutputRoutingChannels": [
{
"name": "Master",
"outputId": "26"
}
]
}Update Track (ppal-update-track)
- Change track gain (volume), panning, and send levels, several sends at once with
sends: [{return, gainDb}](each return named by id, exact name, or letter) - Change mute, solo, arm, I/O routings, and monitoring state
- Change track name and color
- Add and name take lanes from a lane path:
t2/l+appends one,t2/l2names an existing lane (adding the lanes up to it), andnameis the only param a lane takes - Says when a write overrides arrangement automation: Live then ignores that lane until you press Re-Enable Automation
- Update multiple tracks at once
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | track or take lane id(s), comma-separated |
path | string | track or take lane path(s) to update instead of id, comma-separated: 't<index>' (t0 is the first track, so a user's "track 3" is t2), 'rt<index>' (return), 'mt' (main), 't<index>/l<lane>' (a take lane, creating the lanes up to it), 't<index>/l+' (append a take lane). A lane takes only name - e.g. 't0,rt1' or 't2/l+' |
name | string | name, ideally unique, or comma-separated one per target |
color | string | #RRGGBB, or comma-separated one per target |
gainDb | number | track gain in dB |
pan | number | 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) |
mute | boolean | muted? |
solo | boolean | soloed? |
arm | boolean | record armed? |
inputRoutingType 🐘 | string | name from availableInputRoutingTypes, set before channel; or comma-separated one per target (write a comma in a name as ,) |
inputRoutingChannel 🐘 | string | name from availableInputRoutingChannels; or comma-separated one per target (write a comma in a name as ,) |
outputRoutingType 🐘 | string | name from availableOutputRoutingTypes, set before channel; or comma-separated one per target (write a comma in a name as ,) |
outputRoutingChannel 🐘 | string | name from availableOutputRoutingChannels; or comma-separated one per target (write a comma in a name as ,) |
monitoringState 🐘 | "in" |"auto" |"off" | input monitoring |
sendGainDb 🐘 | number | send gain in dB, requires sendReturn |
sendReturn 🐘 | string | return track, as read-track reports it (return/returnId): id, exact name (e.g., "A-Reverb"), path (e.g., "rt0"), or letter (e.g., "A"); or comma-separated one per target |
sends 🐘 | array | several sends at once: [{return, gainDb}], return as for sendReturn. Use instead of sendGainDb + sendReturn |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"id":"103","mute":false,"gainDb":-3}:
{
"id": "103",
"path": "t2"
}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
| Parameter | Type | Description |
|---|---|---|
path | string | where they go: 's+' appends, 's<index>' inserts there (s0 is the first scene, so a user's "scene 3" is s2). Comma-separated for several, one entry per scene, in order (e.g. 's+,s+' appends two, 's2,s2' inserts two at 2). Required when capture=false. With capture=true it takes one entry, and with none the new scene goes after the selected scene |
capture 🐘 | boolean | copy playing session clips instead of creating empty? |
name | string | name, or comma-separated one per scene |
color | string | #RRGGBB, or comma-separated one per scene |
tempo 🐘 | number | BPM (-1 disables) |
timeSignature 🐘 | string | N/D (4/4) or "disabled", or comma-separated one per scene |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"s2","name":"Chorus"}:
{
"id": "602",
"path": "s2"
}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
| Parameter | Type | Description |
|---|---|---|
id | string | scene id(s), comma-separated |
path | string | scene path(s) to read, comma-separated: 's<index>', where s0 is the first scene (a user's "scene 3" is s2) |
include | array of:"clips" |"notes" |"sample" |"timing" |"warp" 🐘 |"color" |"*" 🐘 | clips = clip list. notes, sample, timing, warp = clip detail (use with clips). color = scene + clip color. "*" = all |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"s1","include":["*"]}:
{
"id": "202",
"path": "s1",
"name": "Verse",
"color": "#B87A35",
"tempo": 96,
"timeSignature": "6/8",
"clips": [
{
"id": "302",
"type": "midi",
"name": "Bass Line",
"color": "#B87A35",
"path": "t1/s1",
"timeSignature": "4/4",
"looping": true,
"start": "1|1",
"end": "3|1",
"length": "2bar",
"notes": "v100 n/4d F1 1|1\nv90 n/8 F1 1|3\nv85 n/4 C2 1|4\nv100 n/2 Eb1 2|1",
"trackName": "Bass"
},
{
"id": "303",
"type": "audio",
"name": "Vocal Take",
"color": "#3DC300",
"muted": true,
"path": "t2/s1",
"timeSignature": "4/4",
"looping": true,
"start": "1|1",
"end": "3|1",
"length": "2bar",
"gainDb": -2.6,
"sampleFile": "/Users/example/Music/Samples/Vocal Take.wav",
"sampleLength": 352800,
"sampleRate": 44100,
"warping": true,
"warpMode": "complex",
"trackName": "Vocals"
}
]
}Update Scene (ppal-update-scene)
- Change scene name, color, tempo, and time signature
- Update multiple scenes at once
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | scene id(s), comma-separated |
path | string | scene path(s) to update instead of id, comma-separated: 's<index>', where s0 is the first scene (a user's "scene 3" is s2) - e.g. 's0' or 's0,s3' |
name | string | name, or comma-separated one per scene |
color | string | #RRGGBB, or comma-separated one per scene |
tempo | number | BPM (-1 disables) |
timeSignature | string | N/D (4/4) or "disabled", or comma-separated one per scene |
Example output
Called with {"id":"202","name":"Verse A","tempo":96}:
{
"id": "202",
"path": "s1"
}Clip Tools
Parameters shown use the default notation
The notes parameter on Create Clip and Update Clip is rewritten to match the active notation. The tables below show it in bar|beat, the default. See MIDI Notation for how it reads under MIDI JSON and Stark.
Create Clip (ppal-create-clip)
- Generate MIDI clips with notes, velocities, and timing using custom notation
- Place clips in clip slots or the Arrangement timeline
- Place arrangement clips on take lanes with a
t0/l1[5|1]path - Support for probability, velocity ranges, and complex rhythms
- Apply transforms to shape notes with math expressions
- Create audio clips from a sample file with
sampleFile, and choose whether Live warps it withwarping(see Audio Clips) - Create the scenes up to a clip slot past the last one, reporting them as
created
Parameters
| Parameter | Type | Description |
|---|---|---|
path | string | where the clip(s) go, comma-separated for multiple. 't<track>/s<scene>' is a clip slot (scenes are created up to that index); 't<track>[<position>]' is that spot on the track's arrangement, where a position is bar|beat or loc:<locator name or id>. An arrangement path needs both halves. 't<track>/l<lane>[<position>]' puts it on a take lane, creating lanes up to that index. All indices 0-based, so 't0/s0' is the first track's first scene, and a number the user says is 1-based - their "scene 3" is s2 (e.g., 't0/s0' or 't0[5|1]' or 't0/s0,t1[loc:Chorus]') |
name | string | name, or comma-separated one per path |
color | string | #RRGGBB, or comma-separated one per path |
timeSignature | string | N/D (4/4), default: global time signature; or comma-separated one per path |
start | string | bar|beat position where loop/clip region begins (clip meter); or comma-separated one per path |
length | string | duration, e.g. '4bar' (see Skills). Clip meter. MIDI only, default: next full bar after latest note. Audio clip length comes from the sample. Or comma-separated one per path |
looping | boolean | enable looping for the clip |
firstStart 🐘 | string | bar|beat playback start (looping clips, when different from start; clip meter); or comma-separated one per path |
notes | string | MIDI in bar|beat notation: v0-127 n<dur> [p0-1] note(s) bar|beat(s) - MIDI clips only |
transforms 🐘 | string | transform expressions (parameter: expression per line). Note-count operations (ratchet()/repeat()/split()/merge()) change how many notes exist |
sampleFile | string | absolute path to audio file - audio clips only; or comma-separated one per path (write a comma in a path as ,) |
warping | boolean | audio clips only. Omit and Live decides per its Loop/Warp Short Samples setting, often time-stretching the file to the tempo. false = play the file as rendered. The state Live settled on comes back as warping unless it's the one you asked for |
gainDb | number | audio clip gain in decibels, 0 = unity (ignored for MIDI) |
pitchShift | number | 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) |
auto 🐘 | "play-scene" |"play-clip" | auto-play the new session clip(s) — worth setting whenever the user will want to hear what you made. play-scene launches the whole scene so the new clip stays in sync with the others (it restarts them; say so first). play-clip fires the clip alone |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"path":"t1/s0","name":"Bass Fill","notes":"v100 n/8 F1 1|1 C2 1|2"}:
{
"id": "603",
"path": "t1/s0",
"noteCount": 2,
"length": "1bar"
}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
- Read a session clip's automation envelopes with
include: ["envelopes"](needs the remote script). A clip read showsenvs: truewhen it has some. An arrangement clip's automation is the track's lane, which can't be read
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | clip id(s), comma-separated |
path | string | clip location(s) to read, comma-separated, 0-based: a clip slot 't<track>/s<scene>' (e.g., 't0/s3'), or an arrangement clip covering a position, 't<track>[<position>]' (e.g., 't0[5|1]') |
include | array of:"sample" |"notes" |"color" |"timing" |"warp" 🐘 |"envelopes" 🐘 |"*" 🐘 | notes = MIDI data (muted notes are hidden and counted in mutedNotes; edits leave them alone). timing = loop/start/end markers. sample = audio file info (sampleFile, gainDb, pitchShift). warp = warp settings (sampleLength, sampleRate, warping, warpMode). color. envelopes = clip automation, session clips only (shown as envs: true when a clip has any); needs the Producer Pal remote script and a round trip per parameter, so ask for it by name - "" leaves it out. "" = all the rest |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"id":"302","include":["*"]}:
{
"id": "302",
"type": "midi",
"name": "Bass Line",
"color": "#B87A35",
"path": "t1/s1",
"timeSignature": "4/4",
"looping": true,
"start": "1|1",
"end": "3|1",
"length": "2bar",
"notes": "v100 n/4d F1 1|1\nv90 n/8 F1 1|3\nv85 n/4 C2 1|4\nv100 n/2 Eb1 2|1"
}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 (use
clip.index/clipseq()for per-clip variation when updating multiple) - Change audio clip gain, pitch shift, and warp settings (see Audio Clips)
- Move clips and change their length in the Arrangement, addressing a clip by any position it covers (
t0[5|1], ort0[loc:Chorus]) - Move a clip with
toPath: along its own track, to another track, onto or off a take lane, or back into a session slot. A move Live has no API for re-creates the clip, which costs its automation envelopes; the result says when that applied. A slot past the last scene creates the scenes up to it, reported ascreated - Write clip automation envelopes (needs the remote script and Live 12.4 or later). On an arrangement clip it writes the track's automation over the clip; see Clip Automation. Writing one re-enables the parameter's automation if you had moved the parameter by hand; the result notes when it did
- Convert an audio clip into a new MIDI track with an instrument and a clip of the detected notes (drums, melody or harmony, as Live's Convert to New MIDI Track); needs the remote script
- Split arrangement clips at specified positions
- Update multiple clips at once
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | clip id(s), comma-separated |
path | string | clip(s) to update instead of id, comma-separated: a clip slot 't<track>/s<scene>', or an arrangement clip covering a position 't<track>[<position>]' (e.g., 't0/s1' or 't0[5|1],t2/s3') |
name | string | name, or comma-separated one per clip |
color | string | #RRGGBB, or comma-separated one per clip |
timeSignature | string | N/D (4/4), or comma-separated one per clip |
start | string | bar|beat position where loop/clip region begins (clip meter); or comma-separated one per clip |
length | string | duration, e.g. '4bar' (see Skills); clip meter; or comma-separated one per clip. Without start, a non-looping clip keeps its end and moves its start to fit |
looping | boolean | enable looping for the clip |
duplicateLoop | boolean | double the clip length and copy existing notes (and automation envelopes) into the new half (Live's Duplicate Loop). MIDI clips only. Cannot be combined with start/length - they set the region this doubles, so the clip would end up twice the length you asked for; to double a portion, send start/length in its own call first. preTransforms edit the source before the double; notes/transforms then apply across the full doubled clip |
firstStart 🐘 | string | bar|beat playback start (looping clips, when different from start; clip meter); or comma-separated one per clip |
arrangementLength | string | duration, e.g. '4bar' (see Skills), or comma-separated one per clip. Arrangement clips only; song meter. Lengthening a looping clip tiles copies to fill the span (many clips, not one); for a single clip, set looping false and supply notes for the full length |
arrangementSplit 🐘 | string | comma-separated song positions to cut clips at: bar|beat in song meter, or loc:<locator name or id> (e.g., '9|1, loc:Chorus') - max 32 points. Cuts the clip into separate clips; to cut a held note into separate notes use split() in transforms. One list for every clip, not one per clip: each clip is cut wherever a position falls inside it, and a position outside it is ignored. Arrangement clips only; song meter. Cannot be combined with toPath or arrangementLength - cut in one call, then move/resize the pieces in the next |
toPath | string | where to move the clip(s): a clip slot 't<track>/s<scene>' (scenes are created up to that index), a spot on the arrangement 't<track>[<position>]' (a position is bar|beat or loc:<locator name or id>), a take lane 't<track>/l<lane>[<position>]' (lanes are created up to that index), or '[<position>]' alone to keep the clip's own lane (e.g., 't2/s3' or 't2[5|1],[loc:Chorus]'). A lane with no position keeps the clip's own start. A clip re-created in a slot or on a take lane drops its automation; one moved on the arrangement leaves the track's automation where it was. Comma-separated, one per clip; a lone '[<position>]' moves every clip, each on its own lane |
gainDb | number | audio clip gain in decibels, 0 = unity (ignored for MIDI) |
pitchShift | number | 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) |
warping | boolean | audio clip warping on/off (ignored for MIDI). false resets the region to the whole file and turns looping off; looping:true forces warping back on |
notes | string | MIDI 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 🐘 | string | transform expressions applied AFTER merging notes (broadcast across the clips); newline-separated for multiple. Use clip.index / clipseq() for per-clip variation. Note-count operations (ratchet()/repeat()/split()/merge() - see Skills) change how many notes exist; prefer them over rewriting notes by hand |
preTransforms | string | transform expressions applied to EXISTING notes BEFORE merging any new notes (broadcast across the clips); clear or edit notes already in the clip. 'delete' (alias 'v0') removes: a whole bar ('3|: delete', | wildcard avoids spilling onto the next downbeat), a span ('1|1-2|1: delete'), one pitch ('C1: delete'), a pitch range ('C1-C5: delete'), or all ('delete'); also remap a drum lane ('C1: C4'). Works with or without notes |
envelopes 🐘 | string | clip automation, one '<target>: <notation>' line per parameter, broadcast across the clips. On an arrangement clip it writes the track's automation lane over the clip's span: times run from the clip start, once through, and the clip comes back under a new id. target: a device parameter id (from ppal-read-device, or a ppal-read-clip envelopes entry) or a mixer name - volume, pan, send0, send1... notation: bar|beat points in the clip meter, joined by '/' (straight ramp), '_' (hold, then jump) or '~N' (curved ramp, N from -1 to 1, no space; positive bends above the straight line (fast start), negative below (slow start)), e.g. '1|1 0 / 3|1 0.8 _ 4|1 0.2 ~0.5 5|1 1'. Values are raw, usually 0..1 - not the display units of ppal-read-device min/max. Mixer volume: 0.85 = 0 dB; pan: -1 = hard left, 1 = hard right. Each line REPLACES that parameter's whole envelope; on a session clip a line with nothing after the colon ('472:') clears it (a lane can't be cleared: write a flat line). Needs the remote script (Live 12.4+ to write points). Not on an unwarped session audio clip or a take-lane clip |
convert 🐘 | "drums" |"melody" |"harmony" | audio clips only: make a new MIDI track from each clip, after the other edits (adds a track, shifting the ones after it), with an instrument loaded and a clip of the notes Live detects in the source's place. drums = rhythm of unpitched percussion (Drum Rack); melody = pitches of monophonic audio (voice, solo instrument); harmony = pitches of polyphonic audio (chords, full mix). Needs the remote script. Cannot be combined with arrangementSplit or a move (toPath) |
quantize | number | quantize strength 0-1, default 1 (full snap). Snaps note starts to quantizeGrid. MIDI clips only |
quantizeGrid | "1/4" |"1/8" |"1/8T" |"1/8+1/8T" |"1/16" |"1/16T" |"1/16+1/16T" |"1/32" | grid that note starts snap to: 1/16 (default), 1/8, 1/4, 1/8T, 1/16T, 1/32, 1/8+1/8T, 1/16+1/16T |
quantizePitch 🐘 | string | limit quantization to one pitch (e.g. C3 or D#4), or comma-separated one per clip |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"id":"302","name":"Bass Line A","transforms":"pitch += 12"}:
{
"id": "302",
"noteCount": 4,
"transformed": 4,
"path": "t1/s1"
}Audio Clips
A new audio clip's region comes from its sample, so start, length, firstStart, and looping are MIDI-only on Create Clip and are ignored (with a warning) alongside a sampleFile. timeSignature and the audio properties (gainDb, pitchShift, warpMode, warping) do apply. On Update Clip, start and length reshape an existing audio clip's region normally.
Warping. When you create an audio clip, Live decides for itself whether to warp the sample, following your Loop/Warp Short Samples preference, which no API can read, so the same call can land differently on two machines. Pass warping: false to play the file exactly as recorded or rendered. Omit it and Live still decides, but the result reports which way it went.
warping: false means the same thing on Create Clip and Update Clip: reset the region to the whole file and turn looping off, which is what Live does underneath. Two consequences on Update Clip:
- It erases a
start/lengthsent in the same call. Reshape the region in a follow-up call. looping: trueforces warping back on, so it vetoes awarping: falsesent alongside it, and says so in that clip'sdetail.
Unwarped clips are measured against the sample. Live switches a clip's markers from beats to seconds when warping is off, and reports an unwarped session clip's length as though it were still warped. Producer Pal measures the region from the markers instead, so a 1.2-second one-shot reads as the beats it really occupies at your tempo rather than as 1.2 beats. That's also what keeps Duplicate from tiling copies over audio that's still sounding.
Device Tools
Create Device (ppal-create-device)
- Add native Live devices (instruments, MIDI effects, audio effects)
- Add VST/AU plug-ins and Max for Live devices by name (needs the remote script). The AI finds them with Library
- Place devices on any track type: MIDI, audio, return, or the main track
- 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
- Create a device or rack from a preset (needs the remote script). The preset is found by name anywhere in Live's library (pack drum kits, Sounds racks, custom folders) on Live 12.4+. A name several files share is refused, listing their paths
- Load a sample into a Simpler instrument (Live 12.4+) via
params: [{name: "sample", value: "<path>"}], and set its level with{name: "gainDb", value: <dB>}
Parameters
| Parameter | Type | Description |
|---|---|---|
deviceName | string | device (e.g. "Wavetable", "Drum Rack"), or comma-separated one per path; omit this and preset to list available devices |
preset 🐘 | string | create from a preset (needs the Producer Pal remote script): a preset name, looked up among the device's presets when deviceName is given, else among all; a name not found there is searched across Live's library (Live 12.4+), and a name shared by several files is refused with their paths; or a path from ppal-library. Comma-separated one per path |
path | string | insertion path(s), required with deviceName, comma-separated for multiple (e.g., 't0/d+' or 't0/d+,t1/d+,t0/d0/c0/d+'). 't0/d+' appends; 't0/d1' inserts at 1 (an index past the end is refused). An insert renumbers the chain, so no later entry may be spelled through a chain an earlier one inserts into. 't0/d0/c+' appends a new chain to that rack and loads the device into it (the result reports the index it landed at); 'c<n>' makes the chains up to n. In a Drum Rack a chain belongs to a pad, so use 't0/d0/pC1' or 't0/d0/pC1/c+' for another layer |
name | string | name, or comma-separated one per path |
params | array | applied after creation — array of {name, value}; value in the unit read-device reports, or none. For a Drum Rack, prefix the name with a pad path, e.g. {name:'pC1/sample', value:'<abs file path>'} loads a sample into pad C1 (auto-creates the pad's Simpler) — build a full kit in one call |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"deviceName":"Saturator","path":"t1"}:
{
"id": "604",
"path": "t1/d2"
}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)
- See a rack chain's own volume, pan, and sends when they're not at default
- See which parameters have arrangement automation. Left out, with a reason, while the track plays from Session
- See which of a rack's macros are mapped (needs the remote script)
- Read and write a Simpler's
pitchBendRangeandnotePitchBendRangeas parameters (needs the remote script)
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | device, chain or drum pad id(s), comma-separated |
path | string | path(s) to read, comma-separated (e.g., 't1/d0', 't1/inst', 't1/d0/c0', 't1/d0/pC1', 't1/d0/rc0') |
include | array of:"actions" 🐘 |"chains" |"drum-map" |"drum-pads" 🐘 |"params" |"param-values" |"return-chains" 🐘 |"sample" |"options" |"*" 🐘 | chains, return-chains, drum-pads = rack contents (chains on a Drum Rack gives its pads with their layers). params, param-values = parameters of the addressed device only (read a nested device by its own path). drum-map = pad names keyed by note (drum name in stark, MIDI number in midi-json), plus drumRackPath naming the rack they belong to. sample = Simpler sample file path (flat top-level field; other sample params are in params). actions = device-specific actions for update-device. options = valid pseudo-param values + dynamic catalogs for specialized devices (IR files, sidechain sources, wavetables) + Wavetable mod routes. "*" = all |
maxDepth | integer | Device tree depth for chains/drum-pads. 0=chains only with deviceCount, 1=direct devices, 2+=deeper |
paramSearch | string | Filter parameters by case-insensitive substring match on name (implies params) |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"id":"401","include":["*"]}:
{
"id": "401",
"path": "t0/d0",
"type": "drum-rack",
"name": "Kit",
"detail": "arrangement automation unknown while the track plays from Session",
"parameters": [
{
"id": "4010",
"name": "Device On",
"value": 1,
"min": 0,
"max": 1
},
{
"id": "4011",
"name": "Macro 1",
"value": 0,
"min": 0,
"max": 127
},
{
"id": "4012",
"name": "Decay (Macro 2)",
"value": 64,
"min": 0,
"max": 127
}
],
"drumMap": {
"C1": "Kick",
"D1": "Snare"
},
"drumRackPath": "t0/d0",
"drumPads": [
{
"id": "408",
"path": "t0/d0/pC1",
"name": "Kick",
"pitch": "C1",
"chains": [
{
"id": "402",
"path": "t0/d0/pC1/c0",
"type": "chain",
"name": "Kick",
"color": "#FF4C4C",
"devices": [
{
"id": "403",
"path": "t0/d0/pC1/c0/d0",
"type": "instrument: Simpler",
"name": "Kick"
}
]
}
]
},
{
"id": "409",
"path": "t0/d0/pD1",
"name": "Snare",
"pitch": "D1",
"chains": [
{
"id": "404",
"path": "t0/d0/pD1/c0",
"type": "chain",
"name": "Snare",
"color": "#FF4C4C",
"devices": [
{
"id": "405",
"path": "t0/d0/pD1/c0/d0",
"type": "instrument: Simpler",
"name": "Snare"
}
]
}
]
}
]
}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, revert, and randomize rack macro variations
- A/B Compare with supported devices
- Control chain and drum pad mute and solo state
- Set a rack chain's own volume, pan, and send levels, several sends at once with the same
sendsargument update-track takes - Change the choke group and output MIDI note of drum chains
- Move a drum pad to another pad, keeping its chain trim, choke group, and devices together
- Load a sample into a Simpler instrument (see Create Device above)
- Swap a preset onto a device (needs the remote script), found by name the same way as in Create Device
- Says when a write overrides arrangement automation: Live then ignores that lane until you press Re-Enable Automation
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | device, chain or drum pad id(s), comma-separated |
path | string | comma-separated path(s) (e.g., 't1/d0', 't1/inst', 't1/d0/c0', 't1/d0/pC1') |
toPath | string | move to path ('t2/d+' appends, 't2/d1' inserts at 1, 't0/d0/c1/d+'; 't0/d0/c+' appends a new chain to that rack and moves the device into it). Comma-separated, one per target. To move a whole drum pad, target the pad path (path 't0/d0/pC1', toPath 't0/d0/pD1'); it stays in its rack and layers onto an occupied pad. A device moved alone keeps its chain's trim only into an empty, untouched chain |
name | string | name, or comma-separated one per target (not a multi-layer pad) |
preset 🐘 | string | preset to load onto the device before the rest of the update (needs the Producer Pal remote script): a preset name (searched among that device's presets, then Live's whole library on Live 12.4+), or a path from ppal-library; comma-separated one per target. A preset for another device, or a rack, replaces the device: its id changes and its automation is lost |
params | array | array of {name, value} or {id, value}. name = a param name; id = a param id from read-device; value in display units (enum string, note name, number) — use the unit read-device reports for that param, or no unit at all; a param with no unit takes a bare number. Many params only accept a coarse ladder of values, so a request lands on the nearest one. Every param sent comes back as one entry, in order: id and name alone when it took the value asked for, the value it reads as (plus a detail) when Live kept a different one, or ok:false and why nothing was written. A param named twice is written once, at its last entry; the earlier one comes back with only a detail. For a Drum Rack target, prefix the name with a pad path, e.g. {name:'pC1/sample', value:'<abs file path>'} sets pad C1's sample (auto-creates the pad's Simpler) |
force | boolean | Only when a sample write was skipped for replacing a pad's instrument: true replaces it anyway. |
actions 🐘 | array | Device-specific action(s), function-call syntax: bare name or name(args). E.g. "reverse", "warpAs(4)", "setModulation('Osc 1 Pos','Env 2',0.5)". Every action sent comes back as one entry, in order: the action alone when it ran, plus a detail when there was nothing to do, or ok:false and why nothing happened. An action named twice runs once, at its last mention |
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). Macros come in pairs, so an odd count rounds up; the entry says where the count landed. Lowering hides macros but keeps their mappings; the entry names the mapped ones it hid. |
abCompare 🐘 | "a" |"b" |"save" | AB Compare: switch to 'a' or 'b' preset, or 'save' current to other slot |
mute | boolean | mute state (chains/drum pads only) |
solo | boolean | solo state (chains/drum pads only) |
color | string | #RRGGBB, or comma-separated one per target (chains only) |
gainDb 🐘 | number | chain's own gain in dB (chains only; a pad path works unless the pad has layers, which take a layer path like 't0/d0/pC1/c1') |
pan 🐘 | number | chain's own pan, -1 (left) to 1 (right) (chains only; a pad path works unless the pad has layers, which take a layer path) |
sendGainDb 🐘 | number | chain's send level in dB, requires sendReturn (chains only) |
sendReturn 🐘 | string | rack return chain for sendGainDb: id, exact name (e.g. "a Reverb"), or letter (e.g. "a"), or comma-separated one per target; requires sendGainDb |
sends 🐘 | array | several of a chain's sends at once: [{return, gainDb}], return as for sendReturn. Use instead of sendGainDb + sendReturn |
chokeGroup 🐘 | integer | choke group 0-16, 0=none (drum chains only) |
mappedPitch 🐘 | string | output MIDI note e.g. 'C3', or comma-separated one per target (drum chains only) |
wrapInRack 🐘 | boolean | Wrap device(s) in a new rack (type auto-detected), in series in one chain: MIDI effects, instrument, audio effects, each kind in the order named. One instrument max; MIDI and audio effects together need an instrument |
🐘 = large model only (hidden in small model mode)
Example output
Called with {"id":"406","params":[{"name":"Filter Freq","value":"0.6"}]}:
{
"id": "406",
"path": "t1/d0",
"params": [
{
"id": "4062",
"name": "Filter Freq"
}
]
}Take Lanes
How the tools work with take lanes, which stack alternate versions of an arrangement clip at the same position. Only the active take plays.
- A lane is part of the path:
t2/l0is track 2's first take lane (0-based, and lanes are created up to the index). Plaint2is the main lane. Use it aspathon Create Clip ortoPathon Duplicate. - Naming one lane twice stacks both copies on it, so
toPath: "t2/l0[9|1],t2/l0[13|1]"puts two takes on one lane. A lane per copy is a lane index per copy,toPath: "t2/l0,t2/l1,t2/l2". On a track that already has lanes, start after the last one a prior Read Track reported. Add transforms to vary each one. - A whole lane goes onto another lane in a single Duplicate:
type: "track"withtoPath: "t2/l0"copies every clip at the position it already has. It copies clips only (no devices, routing, mixer settings, or session clips), and the two tracks must match MIDI/audio type. The source is a track (path: "t2", its main lane) or a take lane (path: "t2/l0", or the lane's id). - A take lane goes the other way too: give a take-lane source a bare track
toPath(t2, its own track or another) and its clips are promoted onto that track's main lane, replacing whatever sits at those positions. - Update Track owns the lanes themselves:
path: "t2/l+"adds one,path: "t2/l0"with anamenames an existing one, and a lane takes no other track setting. - Read Track lists take lanes (with the
arrangement-clipsinclude), and reads one on its own from a lane path. - A take-lane clip can leave its lane, for another lane, another track, or a session slot:
toPathon Update Clip moves it, and Duplicate copies it. Live's API can't remove a take-lane clip, so a move leaves a muted(moved) ...clip behind for you to delete in Live. - Putting a clip on a lane, or taking one off, re-creates it: a MIDI clip from its notes, an audio clip from its sample. Envelope automation isn't preserved, and a warped audio clip comes back with the sample's default warp markers. The response says which applied.
- Limits: Producer Pal creates up to 10 take lanes per track; lanes added in Live past that still work. A take-lane clip can't be split, resized, or deleted through tools, and Producer Pal can't pick the active take or comp lanes. All of that stays in Live's UI. Expand the take-lane arrow on a track header to see them.
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 them. It's an 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, or programmatically via POST /config (the npx producer-pal MCP server also accepts a --live-api flag). See the REST API's Live API section for the full operation reference and examples.
Parameters
| Parameter | Type | Description |
|---|---|---|
path | string | Optional LiveAPI path (e.g., 'live_set tracks 0'); one object, not a list |
operations | array | Array of operations to execute (max 50) |
Example output
Called with {"path":"live_set","operations":[{"type":"get-property","property":"tempo"},{"type":"get-child-ids","property":"tracks"}]}:
{
"path": "live_set",
"id": "1",
"results": [
110,
[
"id 101",
"id 102",
"id 103"
]
]
}Spawn Subagent (spawn_subagent)
Built-in chat only. Every other tool on this page is an MCP tool the server provides. This one belongs to the Producer Pal Chat UI, which runs the nested session itself, so it isn't available over MCP, the REST API, or the Agent Skill.
Off by default. Turn it on with the experimental Subagent checkbox under Advanced on the chat's Tools tab. See Subagents for what the cards show, resuming a subagent, and choosing what workers run under.
- Hands a self-contained subtask to a nested assistant with the full Producer Pal toolset, working in the same Live Set
- Several calls in one response run their subtasks in parallel
- A subagent can't spawn its own, and one turn gets at most 10 spawn attempts
- The AI sees only each subagent's final message, labeled with its number
resumeFromgives more work to a subagent that already ran, keeping everything it did and knows, instead of briefing a fresh one
Parameters
| Parameter | Type | Description |
|---|---|---|
task | string | What the subagent should do, with all the context it needs, since it can't see the conversation. With resumeFrom, just the follow-up. |
resumeFrom | number | Number of an earlier subagent to continue instead of starting a fresh one. |
Example output
Called with {"task":"On the Bass track, write a 4-bar bassline into scene 1 that follows the kick pattern in the Drums clip. A minor, eighth notes, root-heavy."}:
[subagent 1]
Wrote a 4-bar bassline to Bass, scene 1, named "Bass A". Eighth notes in A
minor, roots on the kick hits and passing tones between them. I left it
unlooped to match the Drums clip in that scene.The result is plain text, not JSON: the [subagent N] label, then that subagent's own closing message. Pass the number back as resumeFrom to give the same subagent more work. The AI never sees the subagent's tool calls or working notes, only this; the full log stays in the chat UI's card.