agentleFS
elodin-syselodin-sys/elodin/.cursor/skills/elodin-db/SKILL.md

elodin-db

Skill553 starsChanged 5 months agoApache-2.0View on GitHub

Work with Elodin-DB, the time-series telemetry database. Use when running elodin-db, writing client integrations (C, C++, Rust, Python), configuring replication/follow mode, the DB Asset Server / assets ingest, querying data via the Lua REPL, or connecting the Elodin Editor to a database.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Default batches outgoing data into ~1500-byte TCP writes (standard Ethernet MTU):

    line 182
  2. Distinctive:

    Run a simulation on source, follow on target, and add local streams:

    line 190
  3. Very specific:

    Remove data from the beginning or end of a recording.

    line 259

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Elodin-DB

Elodin-DB is a high-performance time-series database for telemetry data. It stores components, messages, and metadata using the Impeller protocol, and serves as the central data bus between simulations, flight software, and the Elodin Editor.

Quick Start

# Install (from source)
just install

# Run the database
elodin-db run [::]:2240 $HOME/.local/share/elodin/db --config libs/db/examples/db-config.lua --log-level warn

# Connect the Elodin Editor
elodin editor 127.0.0.1:2240

# Launch the Lua REPL
elodin-db lua

Running the Database

elodin-db run <bind_addr> <data_dir> [--config <lua_file>] [--assets <dir>] [--log-level <level>]
ParameterExamplePurpose
bind_addr[::]:2240Listen address (IPv4/IPv6 + port)
data_dir$HOME/.local/share/elodin/dbStorage directory
--configlibs/db/examples/db-config.luaLua configuration script
--assets/var/lib/elodin/assetsSource assets/ tree to ingest on fresh DB create (overrides ELODIN_ASSETS)
--log-levelwarnLog verbosity: error, warn, info, debug, trace

Impeller TCP listens on port N (e.g. 2240). The DB Asset Server always binds N+1 (e.g. 2241) and serves {data_dir}/assets/ over HTTP. Do not put a follower Impeller listener on N+1.

Assets and the DB Asset Server

Visual files for schematics live under {db}/assets/{relative_key} and are served at http://host:(tcp_port+1)/{relative_key} while the DB runs. Record once, copy the DB directory, replay anywhere — no separate assets/ tree required on the consumer.

Source asset root (ingest)

On first create of an empty DB, elodin-db run (and Python world.run(..., db_path=…)) copies a source tree into {db}/assets/ once, then writes a .elodin-ingested marker. Later opens skip ingest so recorded/editor assets are never wiped.

Source resolution (CLI --assets wins when set; otherwise):

  1. $ELODIN_ASSETS
  2. <sim_entry>/assets (simulations only)
  3. <cwd>/assets
  4. Nearest ancestor assets/ (simulations only)
# Seed a fresh DB from an explicit tree (Aleph / HITL pattern)
elodin-db run [::]:2240 ./my-db --assets /var/lib/elodin/assets

Conventional keys inside {db}/assets/

Same layout as the simulation asset root (see elodin-simulation skill):

Key prefixContents
*.glb, meshes/…, models/…Meshes referenced by glb path= (rewritten to db:… in stored KDL)
schematics/*.kdlActive schematic (default schematics/main.kdl) and window sub-schematics
skyboxes/manifest.ron + *.cubemap.ktx2Named skyboxes
terrains/…Terrain atlases for world_mesh
color_schemes/…Optional theme JSON (local editor; not required for replay of built-in names)

schematic.active metadata points at the active KDL asset key (usually schematics/main.kdl). Consumers fetch that KDL over HTTP — there is no inline KDL mirror in DB metadata.

Paths and the db: scheme

At record/ingest, local paths like models/jet.glb become db:models/jet.glb in stored schematics. Already-db: / http(s): / icon builtin=… paths are left alone. Keys must not contain ...

Follow mode and assets

Telemetry replicates over Impeller TCP. Assets do not — the follower GETs http://source:(N+1)/__index__ and mirrors missing/changed keys into its own {db}/assets/, then serves them on (follower_port+1).

elodin-db run 127.0.0.1:2240 ./source-db
elodin-db run 127.0.0.1:2242 ./follower-db --follows 127.0.0.1:2240   # assets on 2243
elodin editor 127.0.0.1:2242

Point --follows at the source Impeller port (N), not the asset port.

Verify

curl -sf -o /dev/null -w "%{http_code}\n" http://127.0.0.1:2241/schematics/main.kdl
ls -lh "$DB_PATH/assets/"

Empty assets/ after a sim usually means a temp DB (world.run without db_path / ELODIN_DB_PATH). Mesh 404s mean the source tree was never ingested — re-run against a fresh DB with the correct --assets / ELODIN_ASSETS.

Full reference: docs/public/content/reference/db-asset-server.md

Lua REPL

Interactive database shell for debugging and exploration:

elodin-db lua
db> client = connect("127.0.0.1:2240")
db> client:dump_metadata()
db> :help

Client Integration

C Client

cc examples/client.c -lm -o /tmp/client && /tmp/client

See libs/db/examples/client.c for streaming fake sensor data.

C++ Client

c++ -std=c++23 examples/client.cpp -o /tmp/client-cpp && /tmp/client-cpp

The C++ library is C++20 compatible. See libs/db/examples/client.cpp for subscription example.

Rust Client

See libs/db/examples/rust_client/ for a complete Rust client using Impeller.

C++ Header Generation

Generate the single-header C++20 library with message definitions:

cargo run --bin elodin-db gen-cpp > libs/db/examples/db.hpp

Python (via Simulation)

Simulations automatically create an embedded database, or connect to an external one:

# Embedded (temporary)
w.run(system)

# Explicit path
w.run(system, db_path="./my_data")

# Connect to external DB
w.run(system, db_addr="127.0.0.1:2240")

Follow Mode (Replication)

Replicate data from one database to another over TCP:

# Source database
elodin-db run [::]:2240 $HOME/.local/share/elodin/source-db

# Follower database (replicates from source)
elodin-db run [::]:2241 $HOME/.local/share/elodin/follower-db --follows 127.0.0.1:2240

The follower:

  1. Synchronizes all existing metadata and schemas
  2. Backfills historical component data and message logs
  3. Streams real-time updates as they arrive
  4. Mirrors schematic assets from the source DB Asset Server on port N+1 (see Assets above)

Packet Size Tuning

Default batches outgoing data into ~1500-byte TCP writes (standard Ethernet MTU):

elodin-db run [::]:2241 ./follower-db --follows 127.0.0.1:2240 --follow-packet-size 9000

Dual-Source Example

Run a simulation on source, follow on target, and add local streams:

# Source machine
elodin editor examples/video-stream/main.py

# Target — follow source
elodin-db run [::]:2241 ./follower-db --follows SOURCE_IP:2240

# Target — connect editor
elodin editor 127.0.0.1:2241

# Target — add local video stream
examples/video-stream/stream-video.sh

Merging Databases

Combine two databases (e.g. SITL and real telemetry) with optional time alignment and component prefixes.

# Basic merge with prefixes
elodin-db merge -o merged --prefix1 sitl --prefix2 real ./sitl-db ./real-db

# Align using elapsed offsets from each recording start, in microseconds
elodin-db merge -o merged --prefix1 sitl --prefix2 real \
  --align1 15000000 --align2 14000000 --from-playback-start ./sitl-db ./real-db

Use --from-playback-start only for elapsed offsets from each recording's playback start (recorded start metadata, falling back to the first data timestamp), expressed in microseconds. Values copied with the Editor µs button are raw timestamps: pass them to --align1 / --align2 without this flag. Seconds must be multiplied by 1,000,000 for the CLI; a seconds display is not necessarily relative to recording start.

Copy alignment values from the editor TIME field: click to select, µs copies raw microseconds, Enter seeks to a pasted value (seconds with s, UTC, or plain µs).

Exporting a Database

Offline export to analysis formats or a Foxglove-ready MCAP recording:

# Parquet / arrow-ipc / csv (one file per component)
elodin-db export --format parquet --output ./out ./my-db

# Foxglove-compatible MCAP + generated Foxglove layout JSON
elodin-db export --format mcap --output ./out ./my-db

# Pre-1970 epochs (e.g. Apollo 1969) auto-rebase to t=0 (also if --epoch-offset-us
# would leave samples pre-epoch — MCAP log_time is unsigned)
# Large GLBs (moon.glb) stay attached; model primitive omitted above --max-embed-mb (default 32)
# Follow-entity mesh always embeds. Dynamic arrows go to /scene_dynamic.
elodin-db export --format mcap --max-embed-mb 32 --output ./out ./apollo-db

The MCAP export maps components to JSON channels (/drone/world_pos.q0 message paths), emits /tf from *.world_pos poses (with world→NED/ENU anchors from a schematic coordinate node), publishes foxglove.SceneUpdate one topic per entity (/scene/<id>: GLBs, literal-pose objects with composed translate/rotate, pixel-width line_3d trails, static arrows, world_mesh "globe" → earth.glb) plus ≤30 Hz dynamic arrows on /scene_dynamic/<name> (Foxglove backfills latest-per-topic on panel remount, so shared scene topics silently drop entities), encodes sensor-camera RGBA to H.264 CompressedVideo when video-export is enabled, attaches schematic KDLs/assets, and generates {db}.foxglove-layout.json (per-viewport followTf from look_at, camera offsets incl. translate_world(...), far ≥ 4× distance). Upload with scripts/foxglove-upload.sh or manually via POST /v1/data/upload + PUT then POST /v1/layouts. See elodin-cli.md Foxglove MCAP Export and foxglove-mcap-export-design.md.

Trimming a Database

Remove data from the beginning or end of a recording. Values are in microseconds. Without --output, modifies in place.

# Remove the first 3 minutes from a recording
elodin-db trim --from-start 180000000 ./my-db

# Remove the last 2 minutes from a recording
elodin-db trim --from-end 120000000 --output ./trimmed ./my-db

# Trim 1 minute from the start and 2 minutes from the end
elodin-db trim --from-start 60000000 --from-end 120000000 --output ./window ./my-db

# Preview without modifying
elodin-db trim --from-start 180000000 --dry-run ./my-db

Editor Connection

The Elodin Editor connects to any running database:

elodin editor 127.0.0.1:2240

From a simulation, the editor connects automatically when launched via elodin editor sim.py.

Architecture

Elodin-DB uses the Impeller protocol internally:

  • Components: Time-series data indexed by entity + component name + timestamp
  • Messages: Ordered log entries (commands, events)
  • Metadata: Schema information, entity names, component types

Storage is append-only with configurable retention. The database supports concurrent readers and writers with lock-free data structures.

Key References

  • Full documentation: libs/db/README.md
  • DB Asset Server: docs/public/content/reference/db-asset-server.md
  • C client example: libs/db/examples/client.c
  • C++ client example: libs/db/examples/client.cpp
  • Rust client example: libs/db/examples/rust_client/
  • Lua config example: libs/db/examples/db-config.lua
  • DB architecture docs: docs/public/content/home/db/

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.