Skip to content

Resources and Filesystem

Working with audio resources, file imports, and filesystem access

The context.resources module provides methods for working with audio resources in the Live Set. It also interacts with the filesystem on your behalf — which matters because extensions run under a restricted permission model.

When your extension needs to add an audio file to a Live Set — for example, a file downloaded from an API, generated by an AI model, or selected by the user — you must first import it into the project:

const importedPath = await context.resources.importIntoProject("/path/to/audio.wav");
// Now use the imported path with createAudioClip
const clipSlot = context.getObjectFromHandle(handle, ClipSlot);
await clipSlot.createAudioClip(importedPath, false);

importIntoProject copies the file into the Live project folder so that Live manages it. The returned path points to the imported copy. Always use this returned path — not the original — when creating clips or referencing the file in subsequent API calls.

To get audio data from a track in the arrangement view, use renderPreFxAudio. This renders the pre-effects audio for a given time range and returns a path to the rendered file:

const track = context.getObjectFromHandle(handle, AudioTrack);
const audioPath = await context.resources.renderPreFxAudio(track, startTime, endTime);
// audioPath points to a WAV file in the extension's temp directory
const audioData = await fs.readFile(audioPath);

The rendered file is placed in the extension’s temp directory, which your extension has permission to read.

Extensions run under a permission model that restricts which parts of the filesystem they can access. Your extension can read and write to:

  • Storage directory (context.environment.storageDirectory) — persistent storage for configuration, credentials, cached state, or any data that should survive across Live sessions.
  • Temp directory (context.environment.tempDirectory) — temporary files like intermediate audio, analysis results, or downloads. May be cleaned up between sessions.

Your extension should not access arbitrary paths like the user’s Documents, Downloads, or Desktop folders.

A stricter OS-level sandbox will be introduced in the future. The current permission model exists so that extensions are built to respect filesystem boundaries from the start. If your extension accesses paths outside the allowed set today, it will break when stricter sandboxing is enforced.

All code that your extension runs must stay within the allowed filesystem boundaries. This includes child processes spawned via child_process and code running in native addons — they must respect the same restrictions. Any workaround that accesses files outside the allowed paths is unsupported and will likely break in the future.

If you need to work with a file that lives outside the allowed paths, use importIntoProject — it runs on the host side and can access the file on your behalf.

Downloading a file from an API and adding it to the Live Set:

const response = await fetch("https://api.example.com/audio/generate");
const buffer = Buffer.from(await response.arrayBuffer());
// Write to the temp directory (allowed)
const tempPath = path.join(context.environment.tempDirectory, "generated.wav");
await fs.writeFile(tempPath, buffer);
// Import into the project so Live manages it
const imported = await context.resources.importIntoProject(tempPath);
await clipSlot.createAudioClip(imported, false);

Persisting state across sessions:

const configPath = path.join(context.environment.storageDirectory, "config.json");
// Write config (allowed — storage directory is read/write)
await fs.writeFile(configPath, JSON.stringify({ apiKey: "..." }));
// Read it back in a later session
const config = JSON.parse(await fs.readFile(configPath, "utf-8"));