Skip to content
Euler Docs

Connecting sources

A source is where a project’s raw data lives. Register it once; every run reads from it. Registering a source does not ingest anything and does not spend.

What Euler reads

FormatBecomes
mcap, ros1_bag, ros2_bagepisodes with decoded telemetry and a timing summary per topic
mp4+parquetepisodes with per-frame state and action
hdf5episodes from ALOHA-style and multimodal HDF5 recordings
lerobot_v2, lerobot_v3episodes from an existing LeRobot dataset
assetsone asset per loose video or image (a sibling caption file becomes its task text)
directoryauto-detected: Euler looks at the files and picks one of the above

You rarely need to name the format: a directory or asset source is inspected at run time and routed to the right reader.

Uploading files

In Sources, drag in files or a folder. Large files go up in resumable chunks: each chunk is its own short request, an interrupted upload resumes where it stopped, and the server checks the whole-file hash before it registers the source. From code, the Python and TypeScript SDKs do the same with one call:

from euler_sdk import EulerClient
 
client = EulerClient("https://api.euler.sudotank.com", api_key="<your API token>")
client.upload_file("kitchen-pilot", "/data/session-01.mp4", source_id="session-01")

Behind it are POST /v1/projects/{id}/uploads and its part, status and complete routes. For a small zip there is also the one-request POST /v1/projects/{id}/sources/upload; anything large should use the chunked route.

The parts of an upload that never completed keep taking space until they are discarded: Sources lists unfinished uploads under the drop zone with a Discard button and shows how much space the project uses, and from code GET /v1/projects/{id}/uploads lists them and DELETE /v1/projects/{id}/uploads/{upload_id} removes one. Completing a large upload briefly needs the file’s size free a second time on the storage volume, so discarding abandoned uploads is the first thing to try when completion is refused for lack of space.

To use an uploaded source in another project as well, copy it rather than uploading it again: the source card’s Copy button asks for the project (and, optionally, which files), and only the original files are copied, linked to the same stored bytes where the storage allows. The new project runs its own layers on the copy; annotations stay with the original. From code it is POST /v1/projects/{id}/sources/{source_id}/copy with a target_project_id. Reusing a source in another project has the details.

Your own bucket

Register a bucket prefix and Euler reads it in place; you do not copy data in first.

curl -fsS -X POST -H "Authorization: Bearer $EULER_TOKEN" -H "Content-Type: application/json" \
  "$EULER_BASE_URL/v1/projects/$PROJECT/sources" \
  -d '{"id": "shift-a", "name": "Shift A", "format": "directory",
       "uri": "s3://acme-robot-logs/2026-09/shift-a/"}'
 
curl -fsS -X POST -H "Authorization: Bearer $EULER_TOKEN" \
  "$EULER_BASE_URL/v1/projects/$PROJECT/sources/shift-a/test-connection"

How long recordings become episodes

An action camera worn for a whole shift produces one long file holding many separate stretches of work. With the session split on, Euler cuts each recording into episodes at idle stretches and scene changes, and each episode gets its own clean clip. It is off by default: each recording is one episode.

In SourcesFieldDefaultMeaning
Split long recordings into episodesenabledoffturn the split on
Shortest episodemin_episode_s4 sa shorter piece is merged into its neighbour
Longest episodemax_episode_s120 sa longer piece is divided at its quietest points
Idle stretch that ends onemin_idle_s3 show long nothing has to happen to end an episode
Motion below which it is idleidle_floor0.01motion level (0 to 1) at or below which a frame counts as idle
Also cut at scene changesuse_scene_changesona hard cut in the content ends an episode

Idle material between episodes is dropped. The setting applies to the next run of a source; episodes already made are not re-split.

curl -fsS -X PUT -H "Authorization: Bearer $EULER_TOKEN" -H "Content-Type: application/json" \
  "$EULER_BASE_URL/v1/projects/$PROJECT/ingest/settings" \
  -d '{"episode_split": {"enabled": true, "min_episode_s": 4, "max_episode_s": 90,
                         "min_idle_s": 3, "idle_floor": 0.01, "use_scene_changes": true}}'

A shortest episode longer than the longest is refused with 422.

What Euler keeps from a video

For each video, Euler writes review and processing copies of the clip, a frame map, a motion track and the keyframes. From an action camera that records its own telemetry it also keeps the accelerometer, gyroscope, gravity, orientation and exposure streams on the video’s clock; those drive the sensor graphs and several readiness checks. Location and face streams are kept out of the review screen and out of every export.

Moving a source to another project

A source and its clips belong to one project. To reorganise without re-ingesting, move it: in Sources, the source card’s Move button sends the source, its clips and their finished annotations to another project. Nothing is re-run and nothing is spent.

curl -fsS -X POST -H "Authorization: Bearer $EULER_TOKEN" -H "Content-Type: application/json" \
  "$EULER_BASE_URL/v1/projects/$PROJECT/sources/session-01/transfer" \
  -d '{"target_project_id": "kitchen-pilot-v2"}'

The move is refused, with the reason, unless the target is a different, empty project in the same workspace and no run is active in either project. It works for data uploaded into Euler; a bucket source cannot be moved yet.

Deleting a project deletes the clips uploaded into it, even if another project reads them. The confirmation says so. Move the sources you want to keep first.

Next