6 Python client
sideman.Live is the Python way in: 32 methods over the same engine, paths and vocabulary as the MCP tools. Generated from sideman/client.py so it cannot drift; regenerate with ./scripts/gen_docs.py after changing the client.
The tool reference says what each op does inside Live, and conventions covers the rules they share.
6.1 Index
- Connection —
request,reload - Discovery —
search,describe,canonical_path,count,types,ping - Read / write —
get,set,call,get_batch,set_batch,transaction - MIDI notes —
notes_get,notes_add,notes_modify,notes_remove - Browser —
browser_list,browser_load - Automation —
envelope_get,envelope_insert_step,envelope_clear - Arrangement —
arrangement_list,arrangement_create_clip,arrangement_duplicate_clip - Observers —
observe,unobserve,observers,unobserve_all,poll_events - Other —
warp_markers_set
6.2 Live
Live(host: str = '127.0.0.1', port: int = 9878, timeout: float = 25.0)One Ableton Live instance, addressed by the LOM path grammar.
Connects per request, like the MCP layer: there is no socket to go stale between two notebook cells run minutes apart.
6.3 Connection
6.3.1 request
request(op: str, params: dict[str, Any] | None = None)Send one wire-protocol op and return its unwrapped result.
The escape hatch: every named method below is one line of sugar over this, and any op docs/PROTOCOL.md lists works here by name.
6.3.2 reload
reload()Hot-reload the engine after editing handlers.py. No Live restart.
Tears every observer down first, so anything being watched - by any client - is no longer watched afterwards.
6.4 Discovery
6.4.1 search
search(query: str | None = None, type: str | None = None, root: str = 'live_set', **params)Find paths by name and/or type, both matched as case-insensitive substrings. Give at least one. Returns {count, nodes_visited, truncated, results: [{path, type, name}]}.
The walk is bounded - optional max_results, max_depth, max_nodes - so it cannot freeze Live’s main thread; check truncated. The browser is excluded, because samples alone has thousands of children.
6.4.2 describe
describe(path: str = 'live_set', include_values: bool = True)Discover what exists at a path instead of guessing. Start here.
Returns properties (with current values unless include_values is False), children with their counts, functions, and unavailable: members the type has that THIS instance does not.
6.4.3 canonical_path
canonical_path(path: str)Resolve an alias path to where the object actually lives.
“live_set view selected_track” is whichever track is selected right now; this returns the stable form, “live_set tracks 3”, which is what to store or reuse. is_alias says whether the input was one.
6.4.4 count
count(path: str, child: str)Length of a Live collection. Returns {path, child, count}.
6.4.5 types
types()Census of every LOM type Live exposes and every member of each.
The whole addressable surface, and large - this is the coverage baseline, not a navigation tool. Use describe() to get around.
6.4.6 ping
ping()Check the connection and whether the engine loaded.
Answered by the shell rather than the engine, so it still replies when handlers.py failed to import - the load error is in the result.
6.5 Read / write
6.5.1 get
get(path: str, property: str, **params)Read one property. Returns {path, property, value, type}.
A list longer than 64 reports only {“vector”: true, “count”: N}; optional offset/limit page through one, 512 per page at most, and the window adds items, returned and truncated.
6.5.2 set
set(path: str, property: str, value)Write one property, inside a native undo step. Returns the value read back, which is not always the value sent: Live stores parameter values as 32-bit floats.
For a property holding a Live object rather than a scalar, pass {“path”: “
6.5.3 call
call(path: str, function: str, args: list | None = None, confirm: bool = False, **params)Call a function on a Live object, inside a native undo step. Returns {path, function, result}.
{“path”: “
6.5.4 get_batch
get_batch(specs: list)Read many properties in one round trip.
specs: [{“path”: …, “property”: …}, …]. Returns {count, ok_count, results}; each result carries its own ok/error, so one unavailable property does not lose the other reads.
6.5.5 set_batch
set_batch(specs: list, **params)Write many properties inside one undo step.
specs: [{“path”: …, “property”: …, “value”: …}, …]. Optional stop_on_error (default true) and rollback_on_error (default false). See transaction() for the undo-grouping caveat.
6.5.6 transaction
transaction(ops: list, **params)Run several ops as one undo step, so the user gets one Cmd-Z.
ops: [{“op”: “set”, “path”: …, “property”: …, “value”: …}, {“op”: “call”, “path”: …, “function”: …, “args”: […]}]
Grouping does not cover automatable parameters: tempo, mixer volume, mute and device parameters each form their own undo step in Live even inside an explicit one. Not a database transaction either - Live has no intra-step rollback, so if op 5 fails, ops 1-4 have applied.
6.6 MIDI notes
6.6.1 notes_get
notes_get(path: str, **window)Read a MIDI clip’s notes. Returns {path, count, notes}, each note carrying note_id, pitch, start_time, duration, velocity, mute, probability, velocity_deviation and release_velocity.
Times are in beats, pitch is a MIDI number (60 = C3). The optional window - from_pitch, pitch_span, from_time, time_span - defaults to the whole clip. Keep the note_ids; notes_modify() needs them.
6.6.2 notes_add
notes_add(path: str, notes: list)Add notes to a MIDI clip. Undoable. Returns {path, added}.
Each note: {“pitch”: 60, “start_time”: 0.0, “duration”: 1.0, “velocity”: 100, “mute”: false}. Times are in beats.
6.6.3 notes_modify
notes_modify(path: str, notes: list)Edit existing notes in place. Undoable. Returns {path, modified, unmatched_note_ids} - ids that no longer exist are reported rather than failing the call.
Each entry needs “note_id” from notes_get() plus the fields to change, e.g. {“note_id”: 3, “pitch”: 62, “velocity”: 80}.
6.6.4 notes_remove
notes_remove(path: str, **window)Remove notes in a pitch/time window. Undoable. Returns {path, removed}. The window is the same as notes_get()’s and defaults to the whole clip, so no window removes every note.
6.7 Browser
6.7.1 browser_list
browser_list(path: str = '')Browse Live’s library. Returns {path, item, items}.
An empty path lists the roots - instruments, sounds, drums, audio_effects, midi_effects, plugins, clips, samples, packs, user_library, current_project, max_for_live - and everything below descends by name with “/”.
6.7.2 browser_load
browser_load(path: str, track_index: int | None = None)Load a browser item onto a track. Undoable. Returns {loaded, track}.
A device lands at the END of the track’s device chain; a sample lands in the highlighted clip slot of the selected track, and only while Live is showing the Session view. track_index selects the track and decides nothing else.
6.8 Automation
6.8.1 envelope_get
envelope_get(path: str, parameter: str, **params)Sample a clip’s automation envelope for one parameter. Both arguments are paths: a clip, and the DeviceParameter or mixer control it automates.
Returns {exists, parameter_name, min, max, points: [{time, value}]}, sampled at times or at samples points across the clip (8 by default). Live evaluates a step edge as the end of the step before it, so sample inside a step rather than on its boundary.
6.8.2 envelope_insert_step
envelope_insert_step(path: str, parameter: str, time: float, length: float, value: float)Write a flat automation step, creating the envelope if the clip has none. Undoable. Time and length are in beats; value is in the parameter’s own units, so read its min/max first.
6.8.3 envelope_clear
envelope_clear(path: str, parameter: str | None = None)Clear one parameter’s envelope, or every envelope on the clip if parameter is omitted. Undoable.
6.9 Arrangement
6.9.1 arrangement_list
arrangement_list(path: str)List a track’s Arrangement clips. Returns {path, count, clips}, each clip carrying index, name, start_time, end_time and is_midi. Times are in beats.
6.9.2 arrangement_create_clip
arrangement_create_clip(path: str, start_time: float, **params)Create a clip directly in the Arrangement, from nothing or from a file. Undoable. start_time is in beats.
kind=“midi” (the default) requires length=, in beats; kind=“audio” requires file_path=.
6.9.3 arrangement_duplicate_clip
arrangement_duplicate_clip(path: str, clip: str, destination_time: float)Copy a session clip into a track’s Arrangement at a beat position. Undoable.
An arrangement clip cannot be lengthened afterwards - end_time has no setter - so a long section is tiled, not resized.
6.10 Observers
6.10.1 observe
observe(path: str, property: str)Watch a property and record every change Live makes to it, including changes the user makes by hand in the GUI. Collect them with poll_events().
Not every property is observable; describe() lists what an object actually has. The registry lives inside Live and is shared by every client connected to it.
6.10.2 unobserve
unobserve(path: str, property: str)Stop watching one property. outcome is “removed”, or “object_gone” if the track or clip was deleted first - harmless, Live discarded its listeners with the object.
6.10.3 observers
observers()List active observers, the buffered and dropped event counts, and whether each observed object is still valid.
6.10.4 unobserve_all
unobserve_all()Remove every observer, including ones another client created. Reports leaked: listeners that could not be detached and are still firing inside Live. Should always be 0.
6.10.5 poll_events
poll_events(**params)Collect the change events observe() recorded, oldest first. Returns {count, truncated, reset, gap, oldest_seq, next_since, latest_seq, dropped_events, active_listeners, events}.
The buffer is shared, so start from the latest_seq observe() returned, then pass since=dropped_events means changes were lost between polls.
6.11 Other
6.11.1 warp_markers_set
warp_markers_set(path: str, markers: list, warp_mode: int | None = None)Replace an audio clip’s warp map, turning warping on. Undoable.
markers: [[beat_time, sample_time], …], at least two, beat_times strictly increasing. beat_time is beats from the sample start; sample_time is SECONDS from the sample start, not frames - do not scale by the sample rate.
Typed because Live wants a C++ WarpMarker, which JSON cannot express. Existing markers the new map does not occupy are removed, except the one every clip carries that Live refuses to delete, so remove_failed may be 1.
6.12 Errors
6.12.1 LiveError
LiveError(type_: str, message: str)A refusal from Live or the engine. type keeps the Python exception class name from inside Live, which is load-bearing: PermissionError is the destructive-call guard, AttributeError means the member does not exist.