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.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”: “”} as the value.

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”: “”} anywhere in args names a Live object by path; a plain string is never reinterpreted as one. Destructive functions (delete_, remove_, clear_*, crop) raise LiveError(“PermissionError”) unless confirm=True. Optional offset/limit page a long return value.

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= for only what is new. When truncated, more are waiting: poll again with since=next_since. reset means Live restarted the sequence, so the page starts over; gap means events after since are gone and the page skips them. Optional limit (500 by default) and consume, which removes exactly the returned events from the buffer. It holds 2000 events and drops the oldest first, so a nonzero 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.