4  Tool reference

30 tools, generated from the running registry so it cannot drift.

Signatures and descriptions come from the source; regenerate with ./scripts/gen_docs.py after changing any tool.

4.1 Index

  • Discovery — lom_search, lom_describe, lom_canonical_path, lom_count, lom_types, lom_ping
  • Read / write — lom_get, lom_set, lom_call, lom_get_batch, lom_set_batch, lom_transaction
  • MIDI notes — clip_get_notes, clip_add_notes, clip_modify_notes, clip_remove_notes
  • Browser — browser_list, browser_load
  • Automation — clip_envelope_get, clip_envelope_insert_step, clip_envelope_clear
  • Arrangement — arrangement_list_clips, arrangement_create_clip, arrangement_duplicate_clip
  • Observers — lom_observe, lom_unobserve, lom_observers, lom_unobserve_all, lom_poll_events
  • Other — clip_set_warp_markers

4.2 Discovery

4.2.2 lom_describe

lom_describe(path: str = 'live_set', include_values: bool = True)

Discover everything at a Live Object Model path: properties (with current values), navigable children (with counts), and callable functions.

START HERE. This is how you find out what exists rather than guessing.

Returns an unavailable map for members that exist on the type but not on THIS instance - e.g. a MIDI track has no input_meter_left, only the main track has a crossfader. That is correct Live behaviour, not an error.

Paths are space-separated and zero-indexed, e.g. “live_set tracks 0 mixer_device volume”. Roots: live_set, live_app, app_view.

4.2.3 lom_canonical_path

lom_canonical_path(path: str)

Resolve an alias path to where the object actually lives.

Many paths point at the same object: “live_set view selected_track” is whichever track is selected right now. This returns the stable form (“live_set tracks 3”) which is what you want to store or reuse. is_alias says whether the input was one.

4.2.4 lom_count

lom_count(path: str, child: str)

Count items in a Live collection, e.g. lom_count(“live_set”, “tracks”).

4.2.5 lom_types

lom_types()

Census of every LOM type Live exposes and every member of each.

This is the map of the entire addressable surface. Large - prefer lom_describe for day-to-day navigation.

4.2.6 lom_ping

lom_ping()

Check the connection to Ableton Live and whether the engine loaded.

4.3 Read / write

4.3.1 lom_get

lom_get(path: str, property: str, offset: int | None = None, limit: int | None = None)

Read one property from a Live object.

Example: lom_get(“live_set”, “tempo”) -> 120.0 lom_get(“live_set tracks 0”, “name”) -> “1-MIDI”

A list longer than 64 reports only {“vector”: true, “count”: N}, which hides exactly the long lists worth reading. Pass offset/limit to page through one - Drift’s 66 parameters, a rack’s chains:

lom_get("live_set tracks 0 devices 0", "parameters", limit=25)
lom_get("live_set tracks 0 devices 0", "parameters", offset=25, limit=25)

The window returns items plus count, returned and truncated. Max 512 per page; a limit above that is clamped, not refused.

Use lom_describe first to discover valid member names; do not guess.

4.3.2 lom_set

lom_set(path: str, property: str, value: Any)

Write one property on a Live object. Wrapped in a native undo step, so the user can revert it with Cmd-Z.

Example: lom_set(“live_set”, “tempo”, 128) lom_set(“live_set tracks 0”, “name”, “Drums”)

For a property that holds a Live OBJECT rather than a scalar, name it by path with {“path”: “”}:

lom_set("live_set view", "selected_track",
        {"__path__": "live_set tracks 3"})

Use lom_describe first to discover valid member names; do not guess.

4.3.3 lom_call

lom_call(path: str, function: str, args: list[Any] | None = None, confirm: bool = False, offset: int | None = None, limit: int | None = None)

Call a function on a Live object. Wrapped in a native undo step.

Example: lom_call(“live_set”, “create_midi_track”, [-1]) lom_call(“live_set tracks 0 clip_slots 0”, “fire”)

Some functions take a Live OBJECT, not a scalar - a path string reaches them as a str and Live rejects the call (“did not match C++ signature”). Pass {“path”: “”} for those and it is resolved inside Live:

lom_call("live_set", "move_device",
         [{"__path__": "live_set tracks 5 devices 0"},
          {"__path__": "live_set tracks 7"}, 0])

Markers work anywhere in args, including nested in lists/dicts. A plain string is never reinterpreted as a path, so ordinary string args are safe.

When the return value is a long list it reports only its count. Page it with offset/limit - this is how you read a plugin’s real parameter list, which Live knows even while parameters exposes one entry:

lom_call(dev, "get_parameter_names", limit=50)   -> 50 of 2362 names

When the call returns a Live object that sits directly under path (a new track, a new clip), result_path gives its path, e.g. create_midi_track -> “live_set tracks 5”.

Destructive functions refuse to run unless confirm=True - anything named delete_, remove_ or clear_*, plus crop. Ask the user before setting it.

4.3.4 lom_get_batch

lom_get_batch(specs: list[dict[str, Any]])

Read many properties in ONE round trip instead of N calls.

specs: [{“path”: “live_set”, “property”: “tempo”}, {“path”: “live_set tracks 0”, “property”: “name”}, …]

Never fails as a whole - each result carries its own ok/error, so one unavailable property does not lose the other reads.

4.3.5 lom_set_batch

lom_set_batch(specs: list[dict[str, Any]], stop_on_error: bool = True)

Write many properties inside one undo step.

specs: [{“path”: …, “property”: …, “value”: …}, …] See lom_transaction for the undo-grouping caveat.

4.3.6 lom_transaction

lom_transaction(ops: list[dict[str, Any]], stop_on_error: bool = True, rollback_on_error: bool = False)

Run several ops as one undo step, so the user gets one Cmd-Z rather than N.

ops: [{“op”: “set”, “path”: …, “property”: …, “value”: …}, {“op”: “call”, “path”: …, “function”: …, “args”: […]}]

UNDO CAVEAT (measured on Live 12.2.7, not assumed): 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. Track name, colour and time signature do group. The undo field in the result restates this.

NOT a database transaction - Live has no intra-step rollback, so if op 5 fails, ops 1-4 have already applied. rollback_on_error defaults to FALSE on purpose: it is a mutation on an error path, and if the step captured nothing it would revert whatever the user did beforehand. Prefer to inspect the result and let the user press Cmd-Z.

4.4 MIDI notes

4.4.1 clip_get_notes

clip_get_notes(path: str, from_pitch: int = 0, pitch_span: int = 128, from_time: float = 0.0, time_span: float | None = None)

Read MIDI notes from a clip, with note_id, pitch, start_time, duration, velocity, mute, probability, velocity_deviation and release_velocity.

path is a clip path, e.g. “live_set tracks 0 clip_slots 0 clip”. Defaults cover the whole clip. Keep the note_ids - clip_modify_notes needs them.

4.4.2 clip_add_notes

clip_add_notes(path: str, notes: list[dict[str, Any]])

Add MIDI notes to a clip. Undoable.

Each note: {“pitch”: 60, “start_time”: 0.0, “duration”: 1.0, “velocity”: 100, “mute”: false} pitch is a MIDI note number (60 = C3); times are in beats.

4.4.3 clip_modify_notes

clip_modify_notes(path: str, notes: list[dict[str, Any]])

Edit existing notes in place. Undoable.

Each entry needs “note_id” (from clip_get_notes) plus the fields to change, e.g. {“note_id”: 3, “pitch”: 62, “velocity”: 80}. Returns unmatched_note_ids for ids that no longer exist rather than failing.

4.4.4 clip_remove_notes

clip_remove_notes(path: str, from_pitch: int = 0, pitch_span: int = 128, from_time: float = 0.0, time_span: float | None = None)

Remove notes in a pitch/time range. Undoable. Defaults remove ALL notes.

4.5 Browser

4.5.1 browser_list

browser_list(path: str = '')

Browse Live’s library. Empty path lists the roots (instruments, sounds, drums, audio_effects, midi_effects, plugins, clips, samples, packs, user_library, current_project, max_for_live).

Then descend by name with “/”, e.g. “instruments/Drift” or “plugins/VST3”.

4.5.2 browser_load

browser_load(path: str, track_index: int | None = None)

Load a browser item (instrument, effect, plugin, sample) onto a track.

path is a browser path from browser_list, e.g. “instruments/Drift”. Loads onto the selected track unless track_index is given. Undoable.

4.6 Automation

4.6.1 clip_envelope_get

clip_envelope_get(path: str, parameter: str, samples: int = 8, times: list[float] | None = None)

Sample a clip’s automation envelope for one device/mixer parameter.

path - clip path, e.g. “live_set tracks 0 clip_slots 0 clip” parameter - parameter path, e.g. “live_set tracks 0 mixer_device volume” or “live_set tracks 0 devices 0 parameters 1”

4.6.2 clip_envelope_insert_step

clip_envelope_insert_step(path: str, parameter: str, time: float, length: float, value: float)

Write a flat automation step into a clip envelope, creating the envelope if it does not exist. Times are in beats. Undoable.

4.6.3 clip_envelope_clear

clip_envelope_clear(path: str, parameter: str | None = None)

Clear one parameter’s envelope, or ALL envelopes on the clip if parameter is omitted. Undoable.

4.7 Arrangement

4.7.1 arrangement_list_clips

arrangement_list_clips(path: str)

List clips in a track’s Arrangement, e.g. path “live_set tracks 0”.

4.7.2 arrangement_create_clip

arrangement_create_clip(path: str, start_time: float, length: float = 4.0, kind: str = 'midi', file_path: str | None = None)

Create a clip directly in the Arrangement view. Undoable.

path - track path, e.g. “live_set tracks 0” start_time - position in beats kind - “midi” (uses length) or “audio” (requires file_path)

Returns clip_path, e.g. “live_set tracks 0 arrangement_clips 2”.

4.7.3 arrangement_duplicate_clip

arrangement_duplicate_clip(path: str, clip: str, destination_time: float)

Copy a session clip into the Arrangement. Undoable.

path - track path, e.g. “live_set tracks 0” clip - source clip path, e.g. “live_set tracks 0 clip_slots 0 clip”

4.8 Observers

4.8.1 lom_observe

lom_observe(path: str, property: str)

Watch a property and record every change Live makes to it - including changes the USER makes in the GUI, not just ones made through this server.

Then call lom_poll_events to collect them.

Not every property is observable. If there is no add__listener, this says so; lom_describe lists what an object actually has. Example: lom_observe(“live_set”, “tempo”)

4.8.2 lom_unobserve

lom_unobserve(path: str, property: str)

Stop watching one property.

Returns outcome: “removed”, or “object_gone” if the underlying track/clip was deleted (harmless - Live discarded its listeners with the object).

4.8.3 lom_observers

lom_observers()

List active observers, buffered event count, and whether each observed object is still valid (object_valid: false means it was deleted).

4.8.4 lom_unobserve_all

lom_unobserve_all()

Remove every observer. Reports leaked - the number that could NOT be detached and are still firing inside Live. Should always be 0.

4.8.5 lom_poll_events

lom_poll_events(since: int | None = None, limit: int = 500, consume: bool = False)

Collect change events recorded by lom_observe.

The buffer is shared with every earlier session, so start from the latest_seq that lom_observe returned. Then pass since = the previous next_since to get only new events, oldest first. When truncated is true, more are waiting: poll again with since=next_since. reset true means Live restarted the sequence: the page starts over from the oldest buffered event. gap true means events after since are gone (dropped or consumed by another client) and the page skips them. limit must be at least 1. consume=true removes exactly the returned events.

Check dropped_events: the buffer holds 2000 events and drops oldest first, so a nonzero value means changes were lost between polls.

4.9 Other

4.9.1 clip_set_warp_markers

clip_set_warp_markers(path: str, markers: list[list[float]], warp_mode: int | None = None)

Replace an audio clip’s warp map, turning warping on. Undoable.

path - audio clip path, e.g. “live_set tracks 0 clip_slots 0 clip” markers - [[beat_time, sample_time], …], at least 2, 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.

Cannot be done with lom_call: Live wants a C++ WarpMarker object, which JSON cannot express, so it must be built inside Live.

Existing markers the new map does not occupy are removed. A fresh clip carries a marker Live refuses to delete, so remove_failed may be 1.