Imported from tobi/motorsport-telemetry-rs (
.grok/skills/create-telemetry-sidecar/SKILL.md). Install upstream withnpx skills add tobi/motorsport-telemetry-rs --skill create-telemetry-sidecar. Copyright stays with the author.
MTX sidecar
JSONL only (plain or zstd). Not a .telemetry zip. Each mtx header starts a
folder and governs records until the next mtx header or end of file. There is
no folder record and no k:"f".
The primary key is integer nanoseconds. Normative rules:
crates/telemetry-format/JSONL.md §3 and §11.3.
File
Preferred: Name.telemetry.ext.jsonl or Name.telemetry.ext.jsonl.zstd.
One or more groups, no laps line, no blank lines, compact JSON, LF. Each
group is:
- One complete header object (
mtx, nevermtj). - Zero or more sample channels and/or spans.
Write another complete mtx header to start another folder in the same file.
Each header independently defines the group's q, dur, o, utc, tz,
and optional hash.
Write with write_jsonl_timeline (spans only) or
write_jsonl_extension_from_source (channels). Default write is zstd level 11.
Header (required)
| Key | Type | Meaning |
|---|---|---|
mtx |
1 |
Sidecar document |
n |
non-empty string | Group title, e.g. Sebring 12H 2025 |
q |
integer ≥ 1 | This group's lattice quantum, nanoseconds |
dur |
integer ≥ 0 | Exclusive end of this group's timeline |
vis |
0 or 1 |
1 group starts expanded, 0 starts collapsed |
utc |
integer ≥ 1 | Unix-epoch nanoseconds (UTC) at this group's t = 0 |
tz |
IANA string | Venue timezone for this group. Copy from the host. |
utc is required: Unix-epoch nanoseconds at this group's t = 0. That is how
the group sits on the same axis as the host. Copy host utc and tz when
times are host-relative.
Optional: r (right chrome), o (origin, default 0), hash (host schema
hex). Do not join with clk/abs.
Right chrome r
Left-to-right on the right of the group header. Mix freely:
- Text (descriptions):
{"t":"LMP2 stints during the race"} - Pill (facts):
{"p":["Avg lap","1:52.1"]}
Records
Every MTX record MUST include vis (1 shown when the group is open, 0 hidden).
Sample channel (k omitted or "c")
Same as a recording channel, plus vis:
{"n":"Ride Height FL","hz":100,"u":"mm","vis":1,"v":[42,41],"t0":10000000}
t[i] = t0 + i/hz. t0 defaults to header o. Unique n.
plt is trace (default), gauge, or compass. Foreign signals
(temperature, BPM, SpO2, wind direction) are gauge or compass with
optional sc/rnd/fmt. Do not overlay them on Speed.
Optional lbl only on traces: [[ns,"comment"],…]. Dot on the
trace; hover expands a dotted vertical across the full view height.
Span (k":"s")
An interval, not a sampled signal.
{"k":"s","n":"443-1","s":0,"e":5400000000000,"vis":1,"c":"#e11d48","p":{"title":"#443","sub":"EL · 1:52.1"},"m":[["Laps","28"],["Best","1:50.332"]]}
| Key | Role |
|---|---|
s, e |
[start, end) file-relative ns, lattice points, e > s |
c |
#RRGGBB on the bar |
p.title / p.sub |
Drawn on the span |
m |
Hover only. ["Name", value]. Race times are timespan_ms. |
Do not put hover facts in p. Do not put the title in m.
Race times (Best, Avg, drive time) use timespan_ms: integer milliseconds
0..=360000000 (100 h, u32). Renders M:SS.FFF / H:MM:SS.FFF. Write
["Best",{"v":110332,"u":"timespan_ms"}] so averages are mean(v).
km/h and mph (mp/h) convert; bar and psi convert.
k:"f" is invalid.
Primary key (integer nanoseconds)
Every t0, s, e, dur is file-relative ns on its current group's axis.
That group's header utc (required) is Unix-epoch ns at its t = 0:
absolute_ns = file_relative_ns + utc
host_t = ext_t + ext.utc − host.utc
Usual path: copy host lap/sample_time_ns integers, snap to q, copy
host utc+tz. A stint in lap 3 uses that lap's start_ns, not 0.
Wall-clock instant: s = utc_epoch_ns − host.utc, then copy host utc.
Sidecar-local zero: set sidecar utc to that instant; attach subtracts.
tz is display only. Do not write ISO strings, seconds, or a timezone
inside s/e. Do not join with clk/abs. Full rules: JSONL.md §3,
§11.3.
Example
{"mtx":1,"n":"Sebring 12H 2025","q":1000000,"dur":12600000000000,"vis":1,"utc":1742040000000000000,"tz":"America/New_York","r":[{"t":"LMP2 stints during the race"},{"p":["Avg lap","1:52.1"]}]}
{"k":"s","n":"443-1","s":0,"e":5400000000000,"vis":1,"c":"#e11d48","p":{"title":"#443","sub":"EL · 1:52.1"},"m":[["Laps","28"],["Best",{"v":110332,"u":"timespan_ms"}],["Avg",{"v":112104,"u":"timespan_ms"}],["Total drive time",{"v":5400000,"u":"timespan_ms"}],["Driver License","IMSA"]]}
{"k":"s","n":"443-2","s":5400000000000,"e":12600000000000,"vis":1,"c":"#2563eb","p":{"title":"#443","sub":"MB · 1:51.8"},"m":[["Laps","38"],["Best",{"v":110110,"u":"timespan_ms"}],["Avg",{"v":111804,"u":"timespan_ms"}],["Total drive time",{"v":7200000,"u":"timespan_ms"}],["Driver License","IMSA"]]}
Validate
python3 crates/telemetry-format/scripts/validate-mtx.py PATH.telemetry.ext.jsonl
Schema: telemetry.schema.json at the repo root. Validator:
crates/telemetry-format/scripts/validate-mtx.py. Global copy of both:
~/.agents/skills/create-telemetry-sidecar/.
String lengths (Unicode code points)
Omit the key instead of "". fmt has no whitespace (0.0°C).
| Field | max | Example |
|---|---|---|
n (group, channel, span) |
64 | Sebring 12H 2025 |
u |
24 | mm |
fmt |
16 | 0.0°C |
tz |
64 | America/New_York |
| Label text | 80 | bottomed |
r[].t |
120 | LMP2 stints during the race |
| Pill part | 32 | Avg lap |
p.title / p.sub |
32 / 48 | #443 / EL · 1:52.1 |
m name / value |
32 / 48 | Best / 1:50.332 |
r ≤ 8, m ≤ 16, lbl ≤ 256. Worked examples: repo-root telemetry.schema.json.
Author checklist
- Every group header has
n,vis, requiredutc(Unix-epoch ns at t=0), andtz. rusestfor prose,pfor facts.- Every channel and span has
vis. - No folder objects; another complete
mtxheader starts the next folder. - Times are integer nanoseconds (host file-relative, or epoch minus
host.utc). - No ISO strings, no seconds, no timezone inside
s/e. - Colors are
#plus six hex digits. - Meta values are strings.
- Strings fit the length table;
fmtis0.0°Cnot"0.0 °C".