OPEN SOURCE · APACHE 2.0 · MCP

Bagel.

Ship robots,
not terabytes.

Ask your data. Keep what matters. Query robotics, drone and IoT data in plain English. Every answer is deterministically computed, not guessed by a model. Promote a question into an edge pipeline that keeps the seconds that matter.

You askbundled PX4 sample

> What was the lowest battery voltage on this flight, and when?

Bagel runs · shown to youDuckDB

SELECT min(b.voltage_v) AS min_v,
       max(b.voltage_v) AS max_v,
       arg_min(timestamp_seconds, b.voltage_v)
         - min(timestamp_seconds) AS min_at_s
FROM   "battery_status_0" AS b;

Answer209 samples

21.07 V at +4.8 s

down from 24.64 V at the start of the log.

Or no LLM at allpx4 image · demo

sample.ulg - 41.5s, 2018 messages, 77 topics

Power      ⚠  min 21.07V, largest drop 2.37V at ~t=+4.8s
IMU        ✓  accel_z stddev 1.6x baseline at ~t=+36.8s
GPS        -  skipped: no GPS topic
Data gaps  ✓  no gap > 1.05x median interval

Every number is
a query you can read.

The model chooses the question. DuckDB computes the answer over your actual messages, and Bagel shows you the SQL.

Deterministic

Numbers come from SQL, not from the model.

DuckDB over an Arrow extract of your messages. Every query is shown.

At the edge

Keep the incident. Drop the hours around it.

Pipelines run on the robot or over each bag, and upload only what they keep.

Your model

Claude Code, Gemini, Codex, Cursor, or fully offline.

Bagel is an MCP server. The LLM never enters your control loop.

Start with your task

Bagel by Extelligence is an open-source MCP server for robotics, drone and IoT data. These guides connect a question to its setup, query and evidence.

Ask it

> Is my IMU sensor overheating?

> What is the correlation between current and voltage in /spot/status/battery_states?

> I think the robot hit a pothole. Check for sudden deceleration on the z-axis.

> Keep 10 seconds either side of every hard brake and drop the rest.

> Run that detector on every flight from now on.

How it works

LLMs are excellent at language and unreliable at arithmetic. Bagel keeps them on the side they are good at, and hands the numbers to a database engine.

01 · Understand the source

Bagel reads metadata and topic list to build a high-level picture: what was recorded, at what rate, in what shape.

02 · Interpret the topics

For detail, Bagel selects relevant topics, interprets their structure, and writes messages to an Apache Arrow file.

03 · Query and audit

DuckDB executes generated SQL against that extract, looping until the question is answered. Every query is visible.

generated · shown to you
SELECT time_bucket('5s', ts) AS w,
       min(linear_acceleration_z) AS peak_decel
FROM  "/imu/data"
GROUP BY w
HAVING peak_decel < -10
ORDER BY peak_decel;

Bagel is an MCP server - bring your model of choice. Numbers stay deterministic DuckDB SQL regardless of which client you point at it.

Prefer a local model? Fully offline.

Run Bagel with Ollama and your data and your model both stay on the machine. Tool-calling models tiered by RAM - for example qwen3:8b on a 16 GB laptop.

Local LLMs with Ollama →

Capabilities

Ask in plain language

Query

No per-question pandas script. Describe what you want to know and Bagel figures out where to look, across bags, flight logs, live topics, or time-series tables.

Transparent, deterministic math

SQL

Bagel writes DuckDB SQL over an Apache Arrow extract of your messages. Every query is shown so you can audit it. No black-box LLM arithmetic.

Natural-language pipelines

Edge

"Keep 10s around every hard brake, drop the rest." One sentence becomes an auditable pipeline: previewed, then run once, across a fleet, or standing at the edge.

Dockerized environments

Docker

One container per ecosystem: ROS 2 Kilted through ROS 1 Noetic, PX4, ArduPilot, Betaflight, IoT. No local dependency archaeology.

Extensible with POML

POML

Teach Bagel a new capability with a short POML file. It becomes a reusable, shareable trick that works across every supported format.

Live streams

Live

Attach a pipeline to a live ROS or MQTT subscription and it runs as data arrives: record continuously, keep only what matters.

Exports

Hand-off

Open results in Rerun, PlotJuggler or Lichtblick, or export LeRobot training datasets.

Anomaly labels with Jev

Beta

Learn normal on the robot, screen every window, and ask TypeSafe's Jev to name what doesn't fit. Runbook ↗

Edge reduction

Read guide →

Keep what matters, drop the rest

A robot records more data than you can afford to move. Bagel turns a question into a detector, runs it where the data is recorded, and ships only the windows around real events.

The detector is the same query you previewed interactively. The SQL stays visible, every kept window is logged, and the raw data stays on the robot until you decide otherwise.

Actual Codex terminal showing Bagel’s verified reduced file and message counts

SEE BAGEL WORK / 001

Keep the incident.
Drop the hours around it.

Two hours of synthetic telemetry became 60 seconds around one simulated event. Every message in the selected window survived. The source stayed intact.

Watch the actual terminal session →

Instead of this

You do this todayAsk Bagel instead
ros2 bag info for metadata"Summarize this bag". Same prompt works on PX4, MCAP, MQTT, Postgres.
ros2 topic echo /imu and eyeball values"What is the peak z-deceleration in /imu, 5s average?" Real SQL: peaks, percentiles, correlations.
Scrub PlotJuggler timelines"Find deceleration under -10 m/s² and cut ±30s snippets". Opens pre-framed in PlotJuggler.
rqt_console, or grep ~/.ros/log"Read the ERRORs from ~/.ros/log". Tracebacks included, no bag needed.
A bash loop over 200 bags"Run this pipeline on every bag in the folder". One pipeline, whole fleet, combined report.
scp / aws s3 sync to ship data off robotUpload to S3, GCS or Azure as a pipeline step, checksum-skipping existing files
parse_bag_final_v7.pyWe need to talk.

Supported data

Request a format →
RoboticsROS 1, ROS 2, MCAP (any profile), ROS text logs
DronesPX4, ArduPilot, Betaflight
AutomotiveASAM MDF4 (.mf4), CAN captures (.blf / .asc + DBC). Beta.
IoTMQTT (live, Sparkplug B), PostgreSQL / TimescaleDB, InfluxDB 3

60 seconds. Go.

Full docs →

Prerequisites: Docker Desktop and an MCP-enabled LLM client. Pick the compose service matching your environment: ros2-kilted, ros2-jazzy, ros2-iron, ros2-humble, ros1-noetic, px4, ardupilot, betaflight or iot.

01 · Clone and start Bagel

terminal
git clone https://github.com/Extelligence-ai/bagel.git && cd bagel
docker compose run --service-ports ros2-kilted

02 · Connect your client

Wait for the server on port 8000, then register it in a new terminal.

terminal
claude mcp add --transport sse bagel http://localhost:8000/sse

03 · Prompt

terminal
claude

> Summarize the metadata of the ROS2 bag "./data/sample/ros2/mcap".

Documentation

Browse all →

Bagel is built in the open. The maintainers hang out in Discord and review pull requests publicly. Request a format, report a bug, sharpen the docs, or land a new capability.

Help Bagel get found

Star the repository on GitHub. It takes 10 seconds and helps the project reach more roboticists, drone engineers, and data teams.

Star on GitHub →