Ableton Extensions Python SDK

Building extensions

Everything you can do from an Extension: menu actions, the object model, transactions, and UI.

The Extension object

app = Extension("My Tool", author="you", version="0.1.0")
# ...register handlers...
app.run()   # connect, register everything, and stay alive handling events

It also exposes services: app.song, app.ui, app.resources, app.environment.

Context-menu actions

Register a function against a scope — the type of object the user right-clicked. Your function receives the resolved, typed object.

@app.context_menu("MidiClip", "Quantize to scale")
def quantize(clip: MidiClip):
    ...

Available scopes: MidiClip, AudioClip, MidiTrack, AudioTrack, ClipSlot, Scene, Simpler, Sample, DrumRack.

context-menu-multi
Multiple actions on one scope.

Commands & selection

@app.command("do_thing")            # invocable by id
def do_thing(): ...

@app.on_selection("ArrangementSelection")   # acts on the current arrangement selection
def on_sel(selection): ...

The object model

Everything is a Pythonic wrapper. Properties map to reads; setters write; methods do actions.

track = app.song.tracks[0]
track.name = "Drums"
clip = track.arrangement_clips[0]
clip.looping = True
clip.color = 0xFF8800

device = track.insert_device("Reverb", 0)
device.parameters[1].value = 0.5

parent = clip.parent     # navigate up: clip → track

See the full API reference.

Transactions = one undo step

Wrap several mutations so Live records them as a single undo.

with app.transaction():
    c1 = track.create_midi_clip(0, 4)
    c2 = track.create_midi_clip(4, 4)
    c3 = track.create_midi_clip(8, 4)
# Ctrl+Z removes all three at once
Read outside, write inside. Do your reads first, then put the writes in the transaction block — reads inside a transaction aren't guaranteed.

Dialogs

For the common cases, ask for input in pure Python — no HTML, no JavaScript:

name = app.ui.prompt("Clip name", default=clip.name)   # text input; None if cancelled
if app.ui.confirm("Delete all clips?"): ...               # yes / no -> bool
scale = app.ui.choose("Scale", ["Major", "Minor", "Dorian"])  # dropdown
dialog
A dialog, rendered by Live — built from one line of Python.

Custom dialogs

Need a bespoke UI? Live renders dialogs as HTML webviews (same as Ableton's own SDK). Pass raw HTML to app.ui.modal(html, w, h) — a send(value) function is injected for you, so your markup just calls send(...) to close and return a value. No postMessage plumbing.

Progress dialogs

Show a progress bar for long work; the callback gets an update function and a cancel signal.

def work(update, abort):
    for i in range(5):
        if abort.is_set(): break
        update(f"Step {i+1}/5", (i+1)*20)
        ...
app.ui.progress("Working…", work)
progress
A native progress dialog driven from Python.

Resources: audio in & out

path = app.resources.import_into_project("/tmp/loop.wav")   # copy a file into the Set
clip = audio_track.create_audio_clip(path, 0.0)

wav  = app.resources.render_pre_fx_audio(audio_track, 0.0, 4.0)  # render a range to WAV
Ableton Extensions Python SDK · MIT · GitHub