Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
get_sessionA

Survey the running set: script handshake, song fields, tracks, clips, devices.

The call to make first. It proves the Remote Script is answering before anything
else is attempted, and it hands back the track and scene indices every other
tool here is addressed by.

Returns:
    Dictionary with script handshake info, song fields, the track list with its
    indices, group track indices, and clip and device detail where asked for.

Note:
    The round-trip handshake takes about 450 ms, so this is the expensive read. Take
    it once at the start and narrow with get_track, get_clip and get_devices
    afterwards rather than calling this again between edits. Group tracks have no arm
    state ('armed' returns null). If Live collection introspection reports zero
    tracks, index probing is used as a fallback.
get_trackA

Read one track's mixer state, flags, device chain, sends and clip slots.

One track in one round trip, where get_session covers the whole set. Use this to
read a mixer before writing it with set_mix, and get_devices when the device
chain is the only thing wanted.

Returns:
    Dictionary with the mixer fields, the arm state and whether arming applies,
    the device names and count, the send values, the clip slot count and the
    indices of the filled ones, and a per-collection flag saying whether each
    count is exact.

Note:
    ``volume`` and ``panning`` are normalised, not dB: 0.85 is 0 dB (measured),
    and the scale is not linear. ``display`` carries the dB reading where Live
    offered one.

    ``arm`` is read only after ``can_be_armed`` says the question applies,
    because reading it on a group track raises inside Live and would break the
    whole batch (measured). It comes back as ``null`` where it does not apply.

    Device names, send values and which clip slots are filled are measured by
    probing indices in one batch, because Live's collections report no length.
    Read ``counts_exact`` before treating any of those counts as complete.
get_clipA

Read one Session clip's properties: length, loop, warp, pitch, markers, flags.

Returns:
    Dictionary with ``has_clip``, and where that is true the clip path, whether
    it is MIDI, and the property fields. An empty slot answers ``has_clip:
    false`` and says so rather than failing.

Note:
    Notes and automation are not properties: use ``read_clip_notes`` and
    ``read_automation``.

    ``warping``, ``warp_mode`` and ``pitch_coarse`` are reachable only through a
    generic path. Each was read, written, read back and restored on 2026-08-29
    against Live 12.4.5, and all three rows are ``verified``. ``pitch_fine`` is
    read-verified only, and the integer mapping behind ``warp_mode`` is still a
    hypothesis: confirm it against ``clip.available_warp_modes``.

    **An audio clip's times are in seconds while warping is off, and in beats while
    it is on.** ``times_in`` says which, and the per-field ``unit`` follows it. A MIDI
    clip is always in beats. Measured 2026-09-19 against Live 12.4.6 on three
    unwarped clips of one 228.792167 s file: ``loop_end`` read 228.79216666666667 on
    all three, and a write of a larger ``end_marker`` clamped to that same number.

    **Toggling ``warping`` rescales the stored markers and does not undo it.** On the
    same clip, turning warping on took ``end_marker`` from 240.918 to 253.682, a
    factor of 1.05298, and turning it back off left it at 253.682 while ``loop_end``
    returned to the file length. The factor is the clip's own warp tempo over 60
    (1.05298 is 63.18 BPM; another clip moved 0.5704 to 1.1408 at 120 BPM and not at
    all at 60). Every toggle multiplies again, so a clip toggled twice carries markers
    well past the end of its own file and nothing reports it. Read the markers after
    any write to ``warping`` and set them back deliberately.
get_devicesA

List a track's device chain: names, class names, on/off, parameter counts.

Reads the chain and changes nothing in it. The device indices it reports are the
ones set_parameter, delete_device and ``song.move_device`` are addressed by.

Returns:
    Dictionary with the device count and one entry per device carrying its index,
    name, class name, on/off state, parameter count and ``configure_needed`` flag.
    A track with an empty chain answers ``device_count: 0`` rather than an error,
    while an index with no track behind it is refused with ``index_out_of_range``.

Note:
    Read the parameter count first. A third-party plug-in reporting exactly one
    parameter has not been configured, which the ``configure_needed`` flag says
    outright. That is a limit in Live, not in this server, and only Live's GUI
    lifts it. The probe behind that flag settles one question, whether the count
    is exactly one or more than one, so where it could not settle it the count
    arrives as ``parameter_count_at_least`` instead.

    For the parameters themselves, with their ranges and display units, call
    ``describe`` with ``with_parameters=True``: this tool counts them and does
    not list them. For the mixer, sends and clip slots on the same track, call
    get_track instead of adding a second call here.
describeA

Introspect any Live object: class, properties, children, and methods.

The route to the dynamic surface: what a loaded plug-in actually exposes, which
no catalog can know in advance because it is decided at runtime and, for
third-party plug-ins, by what the user picked up in Configure mode.

Returns:
    Dictionary with the object class, its properties, its child collections, the
    methods the allowlist permits, and the parameter survey where asked for.

Note:
    Prefer this over lom_describe for a device, and prefer lom_describe for
    anything else. The difference is ``with_parameters``: lom_describe reports a
    device's parameters as a count, and a count is what a Live ``Vector`` that
    refuses ``len()`` fails to give, so a plug-in with parameters can be reported
    as having none. Measured against Live 12.4.5. When that happens this tool
    falls back to probing parameter indices, reports the names it found, and says
    which of the two answers you are looking at.

    Methods are never callable through a path. Take the name from here and invoke
    it through lom_call, which accepts only names on the Remote Script's own
    allowlist. For a device parameter, set it with set_parameter rather than
    writing the path by hand.
create_trackA

Insert a MIDI, audio, or return track and return its resolved index.

Returns:
    Dictionary with the resolved index of the new track, its kind and name, and
    the track count before and after.

Note:
    Inserting at index N shifts the track that was at N, and every track after it, up
    by one. Every track index held from before the call is then wrong, including ones
    in a plan not yet executed. Append with -1 where the position does not matter, and
    otherwise take the resolved index out of this answer rather than assuming it.

    Creating a track does not put an instrument on it. Select it and call
    load_device for that, then create_clip for something to play.
load_deviceA

Search Live's browser and load a device onto a track: a search step, then a load step.

Returns:
    Dictionary of search candidates and the selected track on the search step,
    or the load result and the resulting device chain on the load step.

Note:
    A load cannot be aimed inside a rack: measured 2026-09-07 against Live 12.4.5,
    ``rack.view.selected_chain`` read back as written and the device still landed on the
    track. An effect is appended; an instrument replaces the one already there and
    discards it silently, with its settings and the clip envelopes pointing at it: check
    with get_devices first. Loading plug-ins in rapid succession can crash Live
    (measured: a batch load during a plug-in rescan with a licence dialog open took Live
    down), so load one at a time. A load also arms the target track and disarms every
    other one (measured 2026-09-19 against Live 12.4.6: of two armed tracks and an
    unarmed target, the target came back armed and the others disarmed), and nothing
    here reports it. An instrument load renames a track that still has Live's default
    name; an effect never renames.

    Success means the call ran, not that the track sounds: a measured Drum Rack load
    reported success on a silent track, and an empty rack is what that looks like, so
    read ``song.tracks[N].devices[i].chains``, which get_devices does not report. A null
    ``selected_track_same``, ``displaced`` or ``configure_needed`` means the comparison
    failed, not ``false``; the first compares name and track count, not identity.
    ``loaded_device_index`` is the position of the new device, computed only where
    the two chains single out exactly one, and null otherwise.
    ``status: incomplete`` with no candidates means the walk stopped early, not that the
    item is absent: retry ``unreached_roots``; only ``complete`` rules it out. The main
    track has no index: write ``song.view.selected_track`` with ``{"__path__":
    "song.master_track"}`` through lom_set, then load.
create_clipA

Create an empty MIDI clip of a given length in a Session slot.

The target must be a MIDI track. An audio slot takes a sample instead, which is a
different call: lom_call with path='song.tracks[N].clip_slots[M]',
method='create_audio_clip' and one absolute file path (catalog row
clip_slot.create_audio_clip).

Returns:
    Dictionary with the creation status, the clip path, and the read-back length.

Note:
    An occupied slot is refused rather than overwritten, so nothing is lost by
    aiming at the wrong slot. To replace a clip, delete_clip first.

    The clip arrives empty. Fill it with write_clip_notes, and copy it onto the
    Arrangement timeline with arrange once it holds something.

    Live gives a new Session clip a loop: ``looping`` reads back true with
    ``loop_start`` at 0 and ``loop_end`` at the length asked for. That is Live's
    own default for Session clips and this does not set it. Turn it off through
    ``lom_set`` on ``clip.looping`` where the part is to play once.
delete_clipA

Delete the clip in a Session slot, its notes and envelopes with it.

Requires confirm=True. With confirm=False it reports the clip name, length and
note count that the call would remove, and changes nothing.

Returns:
    Dictionary reporting the deletion, or the loss report when unconfirmed.

Note:
    This empties one Session slot. Slot indices do not shift, so nothing else
    moves and no other index goes stale.

    Emptying a clip is not the same as deleting it: write_clip_notes with an
    empty list and mode='replace' leaves the clip in place with its length,
    loop and envelopes intact. Prefer that where the slot should stay filled.
    A clip already copied into the Arrangement by arrange is a separate clip and
    survives this.
delete_trackA

Delete a track with everything on it. Requires confirm=True.

The widest deletion here: the devices, every Session clip and every Arrangement
clip on that track go with it. With confirm=False it reports the track name, the
devices, the filled Session slots and the Arrangement clip count the call would
remove, and changes nothing.

Returns:
    Dictionary reporting the deletion, or the loss report when unconfirmed.

Note:
    Deleting shifts every later track down one index, so any track index read
    before this call is wrong afterwards. Re-read with get_session, and where
    several tracks are going, delete from the highest index downwards so the
    earlier indices stay valid.

    For something narrower, delete_clip empties one slot and delete_device takes
    one device out of the chain, neither of which renumbers anything.
delete_deviceA

Delete one device from a track chain, its settings with it.

Requires confirm=True. With confirm=False it reports the name of the track, and
the device's name, class and parameter count, and changes nothing.

Returns:
    Dictionary reporting deletion status or pending loss report.

Note:
    The track is named in the report because a device name does not identify
    one. A device class like Utility or EQ Eight sits on several tracks in a
    normal set, so a loss report naming only the device reads the same whether
    the index points at the intended chain or at a neighbour's. Check the track
    name against the one you meant before confirming.

    Deleting shifts every later device in the chain down one index, so a second
    delete aimed at an index read before the first one lands on a different
    device. Read the chain again with get_devices between deletes.

    Two neighbouring intentions are not this tool. To reorder a chain nothing
    needs deleting: call ``song.move_device`` through lom_call. To swap the
    instrument on a track, load the replacement with load_device, which replaces
    the instrument already there in one step (measured). Deleting first only
    loses the settings earlier.

    ``kind`` reaches the return and main chains, which are addressed the same way
    get_devices addresses them. A return track carries its own index and the main
    track has none, so ``track`` is not read at all when kind is master.
write_clip_notesA

Write MIDI notes into a Session clip.

Returns:
    Dictionary containing write confirmation, validation reports, and optional diff.

Note:
    Times are in beats and clip-local, so beat 0 is the clip's own start. ``replace``
    (the default) makes the clip match the list given; Live's own note writing appends,
    so without it a second write duplicates a melody (measured: 63 + 23 = 86 notes). Ask
    for ``append`` by name to layer onto an existing performance. An empty list with
    ``replace`` empties the clip but keeps its length, loop and envelopes; delete_clip
    takes all of them.

    A list straight from ``read_clip_notes`` can be written back: the keys in
    :data:`~live_maestro.music.notes.TOLERATED_NOTE_KEYS`, such as Live's ``note_id``,
    are dropped and reported as ``input_keys_ignored``, and every other unrecognised key
    is an error. ``pitch``, ``start_time`` and ``duration`` are never defaulted, so a
    list spelled with ``pos``/``dur`` is refused before anything is sent instead of
    becoming sixteenths stacked on beat 0.

    Times and durations do not come back bit-identical. They return with a deviation in
    both directions, about 4e-7 relative and reproducible to every digit across runs: a
    sent 0.29 reads back as 0.29000010406260407, a sent 0.18 as 0.17999994796869798 and
    a ``start_time`` of 2.29 as 2.290000104062604, while a duration of 0.5 comes back
    exactly. The cause is not established: it is neither a tick grid of 96, 192, 480
    or 960 per quarter, nor a single float32 conversion (float32 of 0.29 is
    0.28999999). At 124 BPM the error is around
    50 nanoseconds, so it matters only for comparison: never test a note time for
    equality. The diff run here uses a tolerance, which is why it reports ``0 changed``
    for values that differ in the seventh decimal.
read_clip_notesA

Read MIDI notes of a Session clip, query a specific window, or count notes.

Returns:
    Dictionary containing notes, count, window parameters, and validation report.

Note:
    Times and positions are clip-local beats. Muted notes are included and carry ``mute:
    true``.

    A single drum clip of 384 notes comes back as 57k characters, past the tool-result
    cap, and ``Clip`` has no ``note_count`` in the LOM, so counting from out here
    otherwise means transferring every note. ``count_only=True`` carries back one
    integer instead. ``pitch_min`` and ``pitch_max`` narrow the read the way time does,
    which is what makes a question like "what sits below this guitar's lowest string"
    answerable on a clip too large to read whole. ``get_notes_extended`` through
    ``lom_call`` takes a pitch window too, but answers with opaque note handles that can
    be counted and not read. With ``count_only`` there is nothing to validate, so
    ``check`` is ignored; with a window, ``check`` sees the window and not the clip.

    Returned notes are sorted by time, then pitch. Live hands them back ordered by
    pitch, which is the one order a musical instruction never means: four notes written
    at beats 0, 1, 2, 3 with pitches 72, 60, 67, 62 come back 60, 62, 67, 72, so taking
    every other entry off the raw list picks alternating pitches rather than alternating
    beats, silently and plausibly. For Live's own order call ``get_notes_extended``
    through ``lom_call``.
quantize_clipA

Quantize MIDI clip note positions and lengths to a specified beat grid.

Reads notes, calculates quantized positions, writes back using mode='replace',
and verifies the result.

Returns:
    Dictionary with the write result, the number of notes moved, and how far.

Note:
    Parameter interactions: ``strength`` scales note displacement towards ``grid`` from
    0.0 (raw timing preserved) to 1.0 (full snap). Use partial strength (e.g. 0.5) to
    tighten timing while preserving human groove feel. Setting ``quantize_ends=True``
    snaps note ends to the grid too, adjusting note lengths. In contrast,
    ``quantize_ends=False`` shifts note onsets only and preserves articulation.

    Quantising modifies notes in place and is not undoable. Read the notes first with
    read_clip_notes if the original unquantized timing might be needed later.

    To shift pitch instead of timing, use transpose_clip. To write custom or micro-timed
    notes off-grid, use write_clip_notes.
transpose_clipA

Transpose a MIDI clip by note pitch or an audio clip via pitch_coarse.

Relative on both paths, so calling it twice with 2 moves the clip by 4 and there
is no absolute target to aim at. A MIDI clip has every note pitch rewritten. An
audio clip is repitched as a whole instead.

Returns:
    Dictionary reporting the transposition, the notes affected, and any that hit
    the range limit.

Note:
    When to use: Shift the overall pitch of an entire clip by a constant semitone offset.
    When NOT to use: Do not use transpose_clip to edit melody contours, re-voice chords,
    or correct scale degrees. Use write_clip_notes instead. Do not use it for timing or
    groove changes, which are handled by quantize_clip.

    An audio clip is transposed by writing clip.pitch_coarse. The write is relative
    there too, because the current value is read first and the semitones added to it,
    so repeated calls do keep climbing. Live documents the bound as -48 to 48 but that
    figure is not from a probe here. The read-back in the answer is the evidence for
    any one write.

    ``out_of_range='clamp'`` and ``'drop'`` both lose information that
    transposing back will not return: clamped notes have collapsed onto one
    pitch and dropped ones are gone. Keep the default 'error' unless the clip
    has been read out with read_clip_notes first.
set_mixA

Set volume, pan, sends, mute and solo on one track in a single round trip.

Every argument is optional and only the ones given are written, so this is the
cheap way to change several mixer controls at once. Read the current state with
get_track first, since the values here are absolute and not relative.

Returns:
    Dictionary reporting each write with its before and after value, and the dB
    display where Live offered one.

Note:
    Volume and pan are normalised, so 0.85 is 0 dB (measured) rather than 85 per
    cent of anything. Read ``display`` in the answer for Live's own dB reading
    instead of converting the normalised number yourself.

    The master track has no mute and no solo. Both are refused there rather than
    silently ignored, and ``track`` is not read at all when kind is master.

    This is the mixer only. For a knob on a device in the chain use
    set_parameter, and for the tempo use set_tempo. To make a mixer control move
    over time rather than jump, write an envelope with write_automation.
set_parameterA

Set one device parameter by index or name and verify the read-back.

Returns:
    Dictionary reporting the write, the parameter index it resolved to, the
    read-back value, and the display string where the device offered one.

Note:
    Parameter values are normalised, not the unit the device displays. Read ``min``
    and ``max`` (``describe`` with ``with_parameters=True``) rather than assuming
    a range.

    The curve from 0..1 onto the displayed unit is not linear and differs per
    device. On one third-party compressor Attack is ``v^4 * 1000 ms``, so writing
    "10 ms" linearly lands at 316 ms, a factor of 30, silently. Where the device
    reports a display, aim with the display. Where it does not (all VST2), write
    normalised and calibrate by eye once.

    A parameter that shows a display also answers ``str_for_value``: lom_call with the
    parameter path, ``method='str_for_value'`` and one value returns the string that
    value would display, and moves nothing. That maps a unit onto the scale without
    deriving the taper by trial (catalog row param.str_for_value).

    A quantized parameter takes discrete steps, so a written 0.5 can legitimately read
    back as something else, and that is reported as a clamp rather than as a failure.
set_parameter_displayA

Set a device parameter by the reading it should show, not by its raw value.

Returns:
    Dictionary reporting the value written, the display it produced, the residual
    error against the target, the unit, and how many probes and round trips it
    took. On refusal, why - including the case where the device reports no units.

Note:
    The inverse of ``set_parameter``, and there is no formula to invert: the curve from
    the raw range onto the displayed unit differs per parameter and is rarely linear. On
    one measured third-party compressor Attack is ``v^4 * 1000 ms``, Ratio is ``20^v``
    and Threshold about ``40 * log10(v)``, so writing 10 at a parameter that displays
    milliseconds lands at 316 ms, a factor of 30, and reports success.

    The taper is sampled, not computed: one batch of probes asks what each raw value
    would read as, the answers are bracketed around the target, a second batch refines
    inside that bracket, and only then is a single value written and read back. Two
    round trips, and nothing in the set moves until that last step. Probing with real
    writes has been measured leaving Delay Feedback at 100 % (self-oscillation) and
    Saturator Drive at 100 % across 20 parameters (catalog row
    return_device.str_for_value); the probes here write nothing. They also stay strictly
    inside the range and never ask at ``min`` or ``max``, where a plug-in's own
    formatting code has crashed Live in native code no try/except reaches
    (docs/limits.md, 'Asking for a display string at an endpoint (Live)').

    Where the device reports no unit this refuses instead of aiming: every VST2 reports
    a bare number (0 of 36 measured), so a display-driven search there would walk the
    control to its end stop and call it a result. Use ``set_parameter`` with a
    normalised value for those and calibrate by ear once. The result is the stored value
    and its display, which is not audibility: a parameter on a device that is switched
    off reads back exactly the same.
write_automationA

Write an automation envelope into a Session clip and verify the read-back.

Turns a handful of breakpoints into a written curve, then reads it back so the
result reports the stored envelope rather than the requested one.

Returns:
    Dictionary reporting the write, how many points were laid down, and the
    comparison between the stored curve and the generated one.

Note:
    Automation lives in Session clips. There is no way to write an Arrangement
    envelope directly here: write it into the Session clip and then copy the clip
    onto the timeline with arrange, which carries the envelope with it.

    A verified write proves the stored curve, never that it is audible. An
    envelope on a parameter of a device that is switched off, or on a muted
    track, reads back exactly as written and changes nothing anyone can hear.

    With ``clear_first=False`` a repeated call layers points onto the ones
    already there, so a retry after an unclear result can leave a curve that
    matches neither attempt. Read it with read_automation before writing again.
    To explicitly clear an envelope without writing new points, use clear_automation.

    Playing the clip leaves the parameter at the value this curve last reached, and
    stopping does not restore it. Capture the statics you care about before the first
    playthrough: once a curve has run, nothing reports the value it covered.
read_automationA

Sample a clip envelope into a list of values and report what it found.

Reads the curve by evaluating it at ``points`` positions, so the answer is a
sampling of the envelope rather than the breakpoints that define it.

Returns:
    Dictionary with the sampled values, the beat range they cover, the value
    range they span, and flags saying whether an envelope exists at all.

Note:
    Automation lives in Session clips, so an Arrangement clip has none to read.
    als_read is the way to see breakpoints in a saved project instead.

    Use write_automation to lay a curve down and clear_automation to remove one.
    A flat result with an envelope flag of false means nothing is automated on
    that parameter, which is not the same as an envelope holding the parameter's
    current value.
clear_automationA

Delete automation envelopes on a Session clip. Requires confirm=True.

With confirm=False it changes nothing and reports the envelope it would remove: its
range, where the low and the high point sit, and how densely it was sampled to find
them. That report covers one named parameter; with all_envelopes it says only whether
the clip is automated at all, because has_envelopes is one flag for the whole clip. To
see which parameters those envelopes belong to, read clip.automation_envelopes with
lom_get and then each automation_envelopes[i].parameter.name.

Returns:
    Dictionary reporting the clearance, or the envelopes that would go.

Note:
    A cleared envelope is gone, and the parameter falls back to whatever value it holds
    outside the clip rather than to the first breakpoint. Sample it with read_automation
    first if the shape might be wanted back, since nothing here restores it.

    The dry run samples the curve rather than reading its breakpoints, so a feature
    narrower than the reported sampling step can still sit between two samples. Where
    the exact shape matters, read it with read_automation at a resolution you choose, or
    read the breakpoints out of the saved file with als_read.

    To change a curve rather than remove it, write_automation with ``clear_first=True``
    replaces it in one call and needs no clearing first.
arrangeA

Copy Session clips onto the Arrangement timeline at beat positions.

Supports two modes:
1. Single placement: specify track, slot, at_beat (and optionally to_track).
2. Batch placements: pass a placements list to duplicate several clips and verify
   each one against the destination track it landed on.

A copy, not a move: the Session clip stays in its slot and the two are separate
clips afterwards, so editing one leaves the other alone. This is how a Session
idea becomes an arrangement, and how clip automation written by write_automation
reaches the Arrangement timeline.

Returns:
    For single placement: dictionary with placement status, destination track,
    clip counts before and after, the beat the clip actually landed on, and the
    clip itself under placed_clip. Both modes identify a placement by comparing the
    destination track before and after, so a clip that was already on the requested
    beat never stands in for one that did not land.
    For placements list: dictionary with per-placement requested_beat, actual_beat,
    ok, and summary counts.

Note:
    Call it once per placement. Repeating the same call adds another copy at the
    same beat rather than replacing the first, so a retry after an unclear result
    needs the clip count in this answer checked first.

    A list retries worse than a single call, not better: a list that half landed
    doubles what landed if it is sent again. 'destinations' carries the clip count
    per destination track before and after, which is the number to check first.

    Use create_clip and write_clip_notes to build the source clip, and
    set_arrangement_time then play to hear where it landed.
set_locatorA

Place or remove an Arrangement cue locator. Requires confirm=True.

This toggles, and that is the whole difficulty with it. Live offers one call,
``song.set_or_delete_cue``, which adds a locator where none exists at that beat
and deletes the one that does, so the same arguments twice leave nothing behind.
Call with confirm=False first to see which of the two would happen.

Returns:
    Dictionary reporting the toggle, and the cue points and their count after it.

Note:
    A locator marks a position for a human reading the Arrangement. It does not
    move the playhead. Use set_arrangement_time to move that, and set_loop to
    mark a region rather than a point.
set_arrangement_timeA

Move the Arrangement playhead to a beat and read the position back.

Writes ``song.current_song_time``. This moves where playback would start. It
does not start it. Use play to begin, or play with ``from_beat`` to do both in
one call.

Returns:
    Dictionary with the write confirmation and the read-back song time.

Note:
    Writing ``song.current_song_time`` is bounded by ``song.song_length``;
    attempting to set a position past ``song_length`` fails with Live error
    ``"Cannot set the Songtime behind the Songlength"``. Transport playback
    in Session view advances freely past ``song_length``.

    Do not sample a moving transport through lom_batch. A read that follows a
    jump inside the same batch still reports the position from before the move,
    and it reports it without an error (see lom_batch). One call per position.
playA

Start transport playback and read back the is_playing status.

Returns:
    Dictionary reporting the start call and the read-back is_playing flag.

Note:
    The read-back proves the transport is running, not that anything is audible:
    a muted track, an empty Arrangement or a track with no instrument all play
    silently. Use stop to halt, and set_arrangement_time to move the playhead
    without starting.

    Leave the transport as it was found. Nothing here stops it on its own, and a
    set left playing keeps playing for whoever is at the machine.

    A Session clip that has played leaves its track in Session view, and the
    track then ignores the Arrangement until Live's Back to Arrangement button
    is pressed. ``song.back_to_arranger`` reports that state and clears it
    when written false (applied asynchronously, taking up to 2 read-back
    attempts for ``read_back: "applied"``).
stopA

Stop transport playback, and optionally every playing Session clip.

Returns:
    Dictionary reporting the transport stop and, where asked for, the clip stop.

Note:
    With ``quantized=True`` the clips stop on the next grid point rather than at
    once, so an immediate read can still show a clip playing without anything
    having gone wrong. Use play to resume playback, or set_arrangement_time(at_beat=0)
    to rewind the Arrangement timeline to the beginning.

    Stopping does not restore a parameter a clip envelope was driving. The envelope
    leaves the parameter at its last reached value and Live keeps no static baseline
    underneath to restore.
set_tempoA

Set the global song tempo in BPM and read back the stored value.

One tempo governs the whole set, Session and Arrangement alike. There is no
per-track tempo. The one other place a tempo can come from is a scene, below.

Returns:
    Dictionary reporting the write and the read-back tempo.

Note:
    A tempo set here does not survive every scene launch. Firing a scene whose
    ``tempo_enabled`` is on writes ``song.tempo`` again from ``scene.tempo``, so
    read ``song.tempo`` back after a launch rather than assuming this one held
    (catalog rows ``scene.tempo`` and ``scene.tempo_enabled``, both read verified
    2026-08-29 against Live 12.4.5).

    BPM is a real unit, which makes this tool the exception among the setters. A
    device parameter is normalised over whatever range the device declares: reach
    those with set_parameter and read ``min`` and ``max`` through ``describe``
    rather than assuming 0..1 (docs/limits.md). Volume, pan and sends are
    normalised the same way, and set_mix carries them.
set_loopA

Move the Arrangement loop brace, or switch looping on and off.

Every argument is optional and only the ones given are written, so the brace can
be moved without touching the switch and the reverse.

Returns:
    Dictionary reporting how many writes were made and the before and after
    values for each of enabled, loop_start and loop_length.

Note:
    The brace only loops the Arrangement transport. It has no bearing on Session
    clip looping, which is a clip property. Read that with get_clip. ``length``
    is a duration and not an end position.

    Calling with no arguments at all writes nothing and reports the current
    brace, which is the cheap way to read it.
als_readA

Read a saved Ableton project (.als) or rack (.adg) from disk.

Returns:
    Dictionary containing project metadata, track list, devices, and automation structure.

Note:
    This is Channel B, a peer of the live connection rather than a fallback. It
    answers two questions the LOM never will: what is in someone else's project, and
    where an envelope's breakpoints actually sit.

    Automation lives in two places and the LOM can read only one of them. Measured
    over the 174-project corpus (docs/limits.md section 9): 52 (30 %) have clip
    envelopes but 159 (91 %) have
    track automation, and a tool that counted clip envelopes alone reported 110 of
    those projects as unautomated. The two layers are reported separately here and
    are never added together.
als_writeA

Edit a saved .als project file on disk. Requires confirm=True.

The target file must not be the one Live currently holds: Live writes its own memory
over the file when it next saves, without a conflict warning, and the edit is gone. Live
running on a different set is fine.

Returns:
    Dictionary reporting write status, changes made, and verification report.

Note:
    ``sidechain`` and ``configure`` reach what the LOM cannot; for the set open in Live
    use ``lom_set``, ``set_parameter`` or ``set_mix`` instead. Measured across the
    174-project corpus (docs/limits.md section 9), 74 of 82 projects in the house/trance
    BPM window use sidechain compression, median 6 wirings each.

    ``configure`` fills a plug-in's parameter strip whatever the strip currently holds.
    Two parameters written into an instance whose strip held nothing came back on reopen
    with their real values, writable through ``lom_set`` with ``read_back: applied``.
    Live allocates 128 slots per instance and leaves them all in the file, so nothing is
    inserted: three fields of an existing element are filled.

    ``attribute`` sets one attribute anywhere in the file, addressed by an ElementTree
    expression. An expression matching more than one element is refused unless ``index``
    picks one, and ``index`` counts the matches of that expression rather than tracks in
    the project: ``.//MidiTrack/Name/EffectiveName`` does not see the audio tracks at
    all. ``als_read`` with ``locate='tempo'`` or ``locate='track_names'`` answers with
    the expression, attribute and index for those fields; otherwise the expression is
    built by hand, and ``confirm=False`` resolves it against the file and reports what
    it selects.
lom_getA

Read one property value by LOM path, with its catalogued meaning.

The single-property read behind every getter here, for the field no getter
exposes. Where the catalog knows the path, the answer carries a ``catalog``
hint, and where it knows that a particular value is a sentinel it carries
``means`` as well: a ``scene.tempo`` of -1.0 reads back as "no tempo set for
this scene" rather than as a tempo below the legal minimum.

Returns:
    Dictionary with path, value, type, an optional display string for a device
    parameter, and the catalog hint and meaning where those exist.

Note:
    A path that is not rooted at song, app or song.view is refused here without
    Live being contacted. A path Live rejects comes back as ``ok: false`` with
    Live's own ``code``, so a missing property is an error rather than a null.

    Reach for a getter first where one exists: get_session for the whole set,
    get_track, get_clip and get_devices for one of each, read_clip_notes for
    notes, read_automation for envelopes. All of them cost one round trip for
    many fields, where this costs one per field. Use lom_batch to read several
    paths in a single trip, lom_describe when the property names are not known
    yet, and lom_set to write.
lom_setA

Write a property value by LOM path and return verification read-back.

The generic write, and the unvalidated one: set_parameter, set_mix and set_tempo check
the catalog first. lom_call takes a method, lom_batch several writes in one round trip.

Returns:
    Dictionary reporting requested, before, after, clamped, and changed status.
    For a device parameter it also carries ``display`` and ``is_quantized``.

Note:
    An out-of-range value is refused out loud and nothing is stored: ``...volume.value =
    1.4`` answers ``live_error "Invalid value. Check the parameters range with
    min/max"`` and leaves 0.85 standing, as do tempo 5000 and panning 5. What the
    read-back catches is quantised snap: ``<Compressor>.parameters[10].value = 0.4``
    (Model: Peak / RMS / Expand) stored 0 and reported ``clamped: true, read_back:
    "clamped", is_quantized: true, display: "Peak"``, so a value between two steps
    silently becomes another. ``is_quantized`` is what separates a snap to a step
    from a clamp to a range.
    A write can apply asynchronously, leaving ``read_back`` at ``not_observed``, which
    is neither ``clamped`` nor a failure; a method call has no read-back at all; and an
    unknown property name is ignored and reported as success, so check ``changed``
    rather than ``ok``. A collection like ``song.tracks`` cannot be assigned: set a
    property on an element instead.

    A Live object cannot travel as a plain value. Where a property holds one
    (``song.view.selected_track``, ``song.view.selected_scene``,
    ``song.view.detail_clip``, ``browser.hotswap_target``, ``clip.groove``, and on a
    device ``input_routing_type`` and ``input_routing_channel``) pass
    ``value={"__path__": "song.tracks[2]"}`` (protocol section 5.4); handed plain JSON
    the first five answer ``not_settable``. The two routing properties take their
    reference out of ``<device>.available_input_routing_types`` and
    ``...available_input_routing_channels``, never a name string.
lom_callA

Invoke an allowlisted method on a Live object.

The escape hatch for the calls that have no tool of their own, such as
``song.move_device`` for reordering a device chain. What it can reach is bounded
by the Remote Script's allowlist, not by this signature.

Returns:
    Dictionary reporting the call and its return value. A refused call names the
    reason, and where a dedicated tool covers the same ground it comes back with
    ``use_instead`` naming that tool.

Note:
    A method call has no read-back, so nothing here proves the effect the way a
    write through lom_set or set_parameter does. Follow it with the matching read
    (get_devices after a move, get_session after a structural change) rather than
    treating a successful return as evidence.

    Prefer the dedicated tool wherever one exists: create_clip, delete_track,
    set_tempo, play and stop all verify what this cannot. Use lom_get and lom_set
    for properties, which are not reachable as methods, and lom_batch to send
    several calls in one round trip.
lom_batchA

Execute multiple raw LOM operations (get, set, call) in a single round trip.

Returns:
    Dictionary containing ordered results for each operation.

Note:
    A batch runs inside one handler call, synchronously on Live's main thread, and is
    capped at 1000 operations (max_ops=1000): a larger one is rejected upfront and never
    truncated. Measured 2026-09-16 against Live 12.4.5 (macOS 26.6.2, four-track set):
    one request costs about 400 ms whatever its size, with 200 ops at 500 ms, 1600 mixed
    reads at 1506 ms and 3200 song.tempo gets at 1718 ms, error_count 0 throughout; past
    the 200-op point the marginal cost is about 0.72 ms per mixed real read and 0.44 ms
    per song.tempo get. Write and call ops were not measured and cost more.

    Nothing Live recomputes between operations is visible to a later operation in the
    same batch: a read after a transport jump still reports the position from before the
    move, and four jumps interleaved with four reads returned four identical pre-jump
    values and no error. That is the failure shape to expect here. It does not raise. It
    returns a clean set of numbers that look like a measurement of a parameter which
    never changes, and the conclusion drawn from them is wrong. Sample a moving
    transport with one call per position, never inside a batch.

    An end_marker write on an Arrangement clip is refused here rather than sent.
    Observed once, 2026-09-10 against Live 12.4.5: the write was accepted without an
    error and end_time did not move; what it read back was never recorded, and
    docs/limits.md section 5 carries the probe that would settle it. ``atomic`` stops at
    the first error but undoes nothing, so read the state back after a partial failure.
    Prefer a dedicated tool where one exists: get_session, get_track, get_devices and
    set_mix batch their own reads and verify, which this does not.
lom_describeA

Reflect on any LOM object: class, properties, children, callable methods.

The raw reflection, reporting what the object itself declares. Use it to find
the property names on an object the catalog does not cover, then read them with
lom_get and write them with lom_set.

Returns:
    Dictionary reporting object class, properties, child collections with their
    counts, and the methods the Remote Script allowlist will let you call.

Note:
    For a device, prefer ``describe`` with ``with_parameters=True``. This tool
    reports a device's ``parameters`` child as a count, and a count is exactly
    what a Live ``Vector`` that refuses ``len()`` fails to give, so a plug-in
    with parameters can be reported as having none. ``describe`` falls back to
    probing indices when that happens and says which answer it is handing back.

    The methods listed here are names, not calls: invoke one through lom_call.
lom_enumsA

Look up the integer behind a named Live enum member.

Live stores an enum property as a bare integer, so a write needs the number and
a read hands back a number that means nothing on its own. This is the lookup in
both directions.

Returns:
    Dictionary of member names against their integer values, or the list of enum
    type names when ``type_name`` is empty.

Note:
    Call this before writing an enum-valued property through lom_set or
    set_parameter, rather than guessing that the members run in the order Live
    draws them. This answers what a type's members are. lom_describe answers
    what properties an object has, and neither answers the other.
find_pathA

Find the mechanism that serves an intent, and the catalog rows when rows serve it.

Returns:
    Dictionary with the chosen route, any matching rows with their paths and docs,
    and the next call to make when rows are not the answer.

Note:
    There are four routes, and which one comes back matters more than the rows do.
    ``catalog_row`` means the rows carry the answer: each hit gives the path template to
    fill in, the access verbs, the full doc, and ``scopes``, the other places the same
    property exists, since track, return, master and chain mirror one another and a clip
    row usually has an arrangement_clip twin. ``writes`` appears when the best row is a
    read-only parameter object and names the sibling that actually takes a value.

    ``device_parameter`` means the answer is a knob inside a device, which this catalog
    cannot enumerate because what a device exposes depends on the device: filter cutoff,
    resonance, attack, threshold and everything else behind a front panel arrive this
    way, with the procedure to reach them.

    ``blocked`` means Live's API cannot do it at all, with what to do in Live instead.
    ``intent_tool`` is reported in the ``tool`` field alongside the rows rather than in
    place of them, because a tool that verifies its own work is the better route to the
    same end but the path is still worth seeing. ``unresolved`` means nothing matched,
    and ``unmatched`` lists the words that found nothing, which is usually where the
    query went wrong.

    A lookup costs about 1.5k tokens instead of the whole catalog. It does not touch
    Live: it reads the catalog only, so nothing here proves anything about the set that
    is open.
find_soundA

Find an instrument or preset in Live's library by what you want it to sound like.

Returns:
    Dictionary with the root that was searched and why, the words that were searched
    for, the ranked candidates each carrying ``item_path``, ``uri`` and ``category``,
    how far the walks got, and the next call.

Note:
    Nothing here has been listened to: the ranking reads the preset's name and the
    browser category in its uri, so load one and listen before believing it fits.
    ``status`` is coverage, not fit: an empty ``candidates`` under ``complete`` does
    mean no name there answers, while ``incomplete`` makes the list a lower bound.
    Measured 2026-09-17 against Live 12.4.6, ``sounds`` completes, ``drums`` completes
    at the depth this tool sends, and ``instruments`` cannot be searched to the end for
    presets, so a negative from that root is never evidence of absence.

    Each word costs one browser walk and blocks Live's main thread, so three are
    searched and the rest named in ``words_not_searched``. ``considered`` is the sum
    of items those walks examined, not the size of the root and not the size of the
    library, so it exceeds either when two words search the same place. Both word
    lists describe the walk, not the library: the ranking scores every intent word,
    and shortened forms, against the names returned, so an unsearched word still
    appears in ``matched``.
    Measured 2026-09-17 against Live 12.4.6, "rhodes" and "moog" match no preset name in
    ``sounds``, and "kick" none in ``drums`` though a folder "Kick" matches under
    ``kind="any"``.

    ``category`` is derived from the uri's fragment rather than read from Live and is
    null where the uri carries none; ``also_in`` names the other categories it was
    filed under. To load one, call ``load_device`` with the candidate's ``load_with``
    block, the target ``track`` and ``confirm=True``, preferring ``item_path``: a
    ``uri`` is walked for again and can run out of budget. Loading an instrument
    silently replaces the one on that track, so read the chain with get_devices first.
fire_sceneA

Fire a scene and report which beat the launch actually lands on.

Returns:
    Dictionary with the launch grid, the song position read on either side of the
    call, and the beat the launch falls on, or both candidate beats where the
    window spanned a boundary.

Note:
    ``fire`` answers that it succeeded and says nothing about when anything starts.
    Live quantises a launch to the next grid boundary, so aiming a scene at a
    particular bar from outside is a race: read the position, decide, fire, and Live
    may already have passed the boundary the decision was made for. Measured against
    Live 12.4.5: a read of ``song.current_song_time`` returned 55.6, the scene was
    fired, and the launch landed at 96 rather than 64, one 8 bar boundary later than
    intended. Nothing in the result said so.

    This does not remove the race, which is Live's and is not reachable from here.
    It makes the landing visible. The position is read immediately before and after
    the call, and the answer names the beat a launch issued at either end of that
    window falls on. Where the two differ, ``certain`` is false and both are given:
    the launch is on one of them and which one is not knowable from outside.

    With quantisation off the launch starts at once, so the window's own ends are
    the answer and the beat is known no better than the window is wide.

    This fires and does not wait. ``is_playing`` read straight afterwards is
    normally false and that is correct, not a failure: nothing has started yet.
transcribe_stemA

Turn a recording of one instrument into notes, cleaned of what it is not.

Returns:
    Dictionary with how many notes were heard and how many survived cleaning, the
    pitch range, the span in beats, a sample of the notes, and the write result
    where one was asked for.

Note:
    **This transcribes pitch, and percussion has no pitch.** A drum kit returns cymbal
    and shell resonances, reporting success: measured on a four minute drum stem, 39
    notes for 488 beats, none of them a kick, and nothing across forty bars of steady
    playing. Never write drums from here. Held material fails the other way: a wavering
    sustained note reads as several, so a pad arrives at the right pitches with a rhythm
    nobody played. Measured 2026-09-19 over four stems in their busiest 20 seconds,
    written attacks ran 3.35 a second against 2.85 onsets on bass, 3.50 against 1.30 on
    a strummed guitar, and 5.35 and 5.30 against 0.10 and 0.55 on pad and keys.

    ``transcription_suspect`` flags that disagreement, ``kind`` says which way, and
    ``transcription_checked`` says whether the comparison ran at all, since it needs a
    macOS-only second decode: elsewhere no warning means nothing. Measured 2026-09-19
    against exported MIDI for five pitched stems, pitch content agreed 93.7 to 96.2
    percent: which notes, not when, the export's own timing having drifted. Harmonics
    are removed where a lower, louder note at the same time explains them;
    ``monophonic`` then leaves nothing sounding at the same time as anything else.
    ``scripts/eval_transcription.py`` recomputes these.

    Writing needs a clip: ``create_clip`` on the target slot first, long enough for the
    whole part, then this with ``confirm=True``. ``span_beats`` runs from beat 0 to the
    last note's end, so a clip of that length rounded up to a bar holds it. Writing
    replaces every note in the clip, with no undo here and no rollback in the LOM: a
    write that fails after the removal leaves nothing.
sound_index_statusA

Is there an index of how this installation's library sounds, and what is in it?

Call this before ``match_sound``. Without an index that tool has nothing to rank
against, and a fresh session has no way of knowing whether one was ever built.

Returns:
    Dictionary with whether an index exists, where it is, when it was built, how
    many items of each kind it carries, which libraries they came from, and what
    was skipped when it was built.

Note:
    The index is built from the audio Ableton renders for its own browser previews,
    which sits beside the content under ``Ableton Folder Info/Previews``. It is not
    committed and it describes one machine: rebuild it by running
    ``live-maestro-index`` after installing or removing packs.
match_soundA

Rank the library by how close each item sounds to a piece of audio you have.

Returns:
    Dictionary with the descriptor taken from the file, the ranked candidates each
    carrying its name, kind, category, library and score, and the call that loads
    the one you pick.

Note:
    A score orders this one answer, lower being closer: not a percentage or a distance,
    and scores from two files do not compare. The order inside one answer is weaker than
    it looks: ``elsewhere_in_the_file`` ranks a second stretch of the same recording to
    show how weak; ``also_elsewhere`` says a candidate came back in both, the one
    reading here that is evidence, not ordering. Measured 2026-09-19 over five separated
    stems in 20 s windows, two windows of one stem shared about one name in ten and the
    descriptor moved by three to six times the whole width of the top thirty. Ranked
    over the whole library, the top candidate shared the probe's family 1 time in 7 at
    20 s and 6 of 20 on 1.5 s slices: a bass stem answers with drum kits and a guitar
    stem with pads; given ``instrument``, the same audio answers with basses and plucked
    guitars. Name the family when you know it: this is a shortlist, not a ranking.

    What is compared is Ableton's preview render of each item, so a busy-riff preview
    describes itself differently from a held-chord one, and nothing here speaks for
    playable range, velocity response or a single note's attack. The match is timbral
    with level removed, so a quiet and a loud take of one sound match exactly; pitch is
    not matched, so a bass line at 50 Hz and the same line at 100 Hz are near
    neighbours. ``analysed`` says where the window landed, with peak and RMS; a silent
    stretch answers ``nothing_to_match``, and without an index this answers
    ``no_index``. To load one, set ``track`` in its ``load_with`` block and call
    ``load_device``: the handle is a name, not a path, so the browser search can return
    more than one item. Check before confirming.
analyze_audioA

Measure the audio itself: loudness, true peak, stereo phase and band balance.

Reads the LiveMaestro Analyzer Max for Live device over loopback OSC; without it this
reports device_not_found with the steps to load it.

- Loudness to EBU R128: momentary 400 ms, short term 3 s, gated integrated since
  reset, range.
- True peak, oversampled, with sample peak, RMS and the crest factor between them.
- Stereo correlation full band and below 120 Hz, and low-end survival of a mono sum.
- Seven band energies on the mono sum, and their weighted centre, not an FFT centroid.

The device reads at its position in the chain, so it belongs last: an effect
after it is not in the reading. A master chain sits before the master fader, so a
master reading matches the output only at 0.0 dB. The two peak figures are maxima
since the last reset and only rise: to measure one, call with
reset=true and no accumulate, let a pass of the material through, then call again.
The averaged figures need no reset. What it proves is what the signal measured
passing the device, not the room.

Every measurement carries the transport state from immediately after it, so a reading
taken mid scene change can be recognised. ``in_transition`` is true while any track
reports fired_slot_index 0 or more, a launch waiting for the next quantization boundary,
and ``tracks_sounding`` counts tracks whose playing_slot_index is 0 or more while the
transport runs, 0 when stopped: clips Live plays, not what is audible. Unreadable state
gives ``transport`` null with a code and one sentence in ``transport_unavailable``, or
not_queried when the analyzer did not answer.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription
catalog_resourceReturn a map of the catalog: counts, areas, status meanings, and how to search it.
session_resourceReturn JSON string snapshot of running Live session state.
limits_resourceReturn system limits specification and documentation reference.

TDQS

A4.2/5.0

Scored across 43 tools

Disambiguation4/5

The tool set is largely distinct, with a clear layered hierarchy: get_session/get_track/get_clip/get_devices nest cleanly, and read/write pairs (notes, automation) are unambiguous. Two pairs could confuse an agent — describe vs lom_describe and set_parameter vs set_parameter_display — but the descriptions disambiguate them explicitly with cross-references, so the boundary is documented rather than left to inference.

Naming Consistency4/5

The vast majority follow a consistent verb_noun snake_case pattern (get_clip, set_tempo, create_track, delete_device, write_automation), with coherent families: set_*, get_*, read_*/write_*, create_*/delete_*, and a clearly prefixed lom_* raw layer. Minor deviations are the bare verbs arrange, play, stop, and describe without the lom_ prefix, though these read as intentional and do not break the overall pattern.

Tool Count4/5

43 tools is well above the typical 3-15 range and would normally signal bloat, but the domain — full control of a DAW — is genuinely broad, spanning session, tracks, clips, notes, automation, devices, mixer, transport, arrangement, library search, audio analysis, and file formats. Each tool has a distinct job and the 7-tool lom_* raw layer earns its place as an escape hatch that keeps the documented surface finite, so the count is high but reasonable.

Completeness4/5

The surface provides full lifecycle coverage for tracks, clips, devices, notes, automation, and transport, with workflow chains explicitly documented (create_track → load_device → create_clip → write_clip_notes → arrange → play). Minor gaps exist — no dedicated save, undo, or live-record tools — but these are reachable one hop away through the documented lom_call/lom_set layer, making them workarounds rather than dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues