Parse anything. Lose nothing silently. Explain everything.
Every sports watch and bike computer saves workouts as .fit files — and real files
are often imperfect: devices crash mid-ride, batteries die during the save, firmware
writes impossible timestamps, sensors drop out. chiptime is recovery-grade FIT
processing: hand it any file, pristine or mangled, and it returns everything
genuinely in there, explains every decision it made, and never invents what isn't.
import chiptime
result = chiptime.parse("inProgressActivity.fit") # crashed 4 hours into a ride
result.ok # True — the ride is back
result.activity.sessions[0].rebuilt # session rebuilt from the records
open("fixed.fit", "wb").write(chiptime.repair("inProgressActivity.fit").data)The repaired file passes platform validation and uploads. The parse result carries a
complete paper trail — provenance[] lists every byte skipped, every field repaired,
every value reinterpreted. Silent data loss is treated as the cardinal sin.
- Parse — sessions, laps, swim lengths, and per-second columnar streams; totals both as the device declared them and recomputed from the data, with disagreements surfaced. Gaps classified (auto-pause ≠ corruption). Unknown messages and fields preserved, never fatal.
- Repair — salvage a damaged file and write back a valid
.fit, self-checked by re-parsing in strict mode. Honest by design: containers are reconstructed, samples never fabricated. - Validate — platform-acceptance checks before you upload.
- Analyze — sport-aware analytics that speak each discipline's language:
$ chiptime analyze zwift_workout.fit --ftp 250
session 1: cycling/virtual_activity
55:11 · 29.61 km · avg 164 W · weighted 175 W · avg HR 136
structure [laps:manual]: 3 x 10:00 @ 194 W rest 3:24
load 45 [power+ftp]
PACING_NEGATIVE_SPLIT: Second half 7.6% faster than the first.
Runs get min/km and splits, swims get min/100m and sets, rowing gets /500m splits. Thresholds and zones come from you or the file — never estimated. Anything not computable is listed with its reason instead of guessed.
- Never lose data silently — every drop and repair lands in
provenance[]. - Deterministic — same bytes in, byte-identical canonical JSON out, on every machine. Safe to hash, diff, cache, and test against.
- Zero ≠ null, always — coasting is
0W (real); dropout isnull(absent). FIT sentinels becomenullbefore any statistic is computed. - Honest non-recovery — what's truly gone is reported gone.
The contract is enforced by a conformance corpus built from a 104-item edge-case taxonomy: 71 public cases (plus a private real-device tier) with committed expected outputs, gating every change in CI. The corpus is also the cross-language contract — the TypeScript implementation (next milestone) must match Python byte-for-byte.
pip install chiptimePython ≥ 3.11 · zero runtime dependencies · fully typed (mypy --strict,
py.typed) · pip install "chiptime[pandas]" adds DataFrame export.
chiptime parse ride.fit --json # canonical JSON
chiptime repair crashed.fit -o fixed.fit
chiptime validate fixed.fit --platform garmin-connect
chiptime analyze swim.fit
chiptime codes # every machine code, explainedStable machine codes for every error, warning, provenance entry, and insight; exit
codes that route control flow; deterministic JSON; llms.txt
and full-corpus markdown for indexing. If your consumer is a program or an LLM, the
interface was designed with it in mind.
Docs: maxgrgrv.github.io/chiptime — getting started · API reference · migration guides · the contract
0.4.0 — Python implementation live: decode + recovery + repair + validation +
analytics, 273 tests, validated against 66 real device files with zero contract
violations. Next: the TypeScript twin on the shared corpus (M3).
MIT. Not affiliated with Garmin; FIT profile tables are generated by our own tooling — no Garmin SDK code or files are included.