Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Physlint

Robot data integrity, before training.

Local-first, deterministic validation for physical-AI recordings and robot-learning datasets.

CI Release Python MIT Status

Quickstart · Demo · Rules · Evidence · Roadmap · Contributing

Physlint public-alpha validation: four of four clean snapshots passed and three of three controlled corruptions were detected across 74 episodes and 31,258 frames.

Physlint finds concrete integrity defects before robot data reaches training. It explains the impact, identifies the affected episode and stream, recommends remediation, writes a stable JSON report, and returns a CI-safe exit code.

The 0.1.0a1 public alpha ships with a publicly validated LeRobot Dataset v3.x adapter. The engine is designed to grow into recording and dataset profiles for MCAP/ROS 2, Robomimic HDF5, RLDS/TFDS, and other physical-AI formats without pretending those adapters already exist.

[!IMPORTANT] Physlint validates configured data-integrity contracts. A pass does not certify policy quality, task success, or robot safety.

Why Physlint?

  • Catch failures before GPU time: malformed manifests, broken episode ranges, reordered clocks, missing values, corrupt video, frozen cameras, and black frames become actionable findings.
  • Keep robot data local: physlint check performs no network requests and never modifies its source dataset.
  • Get evidence, not a mystery score: every finding includes a stable rule ID, severity, source location, observed condition, expected condition, impact, and remediation.
  • Use it in CI: deterministic execution, versioned JSON, atomic report writes, strict configuration, and documented exit codes.
  • Trust scoped claims: the public release gate pins exact dataset revisions and commits sanitized reports, corruption recipes, checksums, and publication metrics.

Quickstart

Physlint requires Python 3.11 or newer.

Install from PyPI

python -m pip install "physlint[video]==0.1.0a1"

Until the package is published to PyPI, install this GitHub release directly:

python -m pip install "physlint[video] @ git+https://github.com/pranayjoshi/physlint.git@v0.1.0a1"

Check a local LeRobot v3 dataset

physlint inspect /path/to/lerobot-dataset
physlint check /path/to/lerobot-dataset

Write JSON to an exact destination:

physlint check /path/to/lerobot-dataset \
  --output json \
  --json-output artifacts/physlint-report.json

The source remains untouched. Exit code 0 means the configured contract passed; 1 means validation completed with a blocking finding.

See it catch a real defect

These captures use the pinned Panda source from the release gate. The second dataset is a fully dereferenced copy with one deterministic NaN injected at episode 0, sample 5, state dimension 0.

Clean pinned snapshot Controlled NaN corruption
Physlint terminal output showing the clean pinned Panda LeRobot dataset passing 11 applicable rules with zero failures and zero errors. Physlint terminal output showing a controlled NaN corruption failing numeric.finite_values with remediation guidance.

Physlint owns NaN and infinity semantics in numeric.finite_values; the same sample is not duplicated as a missing-stream finding.

What Physlint checks

Seventeen deterministic rules are enabled by default:

Area Checks
Manifest Required files, declared/stored schema agreement, required streams, and feature shapes
Episodes Unique identifiers, positive lengths, non-overlapping boundaries, and stored-row agreement
Temporal Strictly monotonic timestamps, FPS cadence, FPS-aware maximum gaps, complete stream overlap, and observation/action delay when independently timestamped
Numeric NaN/Inf, configured physical bounds, and configured discontinuity limits
Video Complete decode, motion-aware frozen-frame runs, and grouped black/near-empty frames

List or explain the installed rule contract:

physlint rules
physlint rules --json
physlint explain temporal.max_gap
physlint explain video.frozen_frames

Rules whose required inputs are unavailable return not_run with a reason; they are never misreported as passed. Robot-specific bounds and discontinuity checks stay not_run until the user supplies meaningful thresholds.

Read the complete MVP rule specifications.

Configuration

Run physlint init to generate a documented quality contract, or create physlint.yaml yourself:

config_version: 1
adapter: auto
required_streams:
  - observation.state
  - action
fail_on: error

rules:
  temporal.max_gap:
    options:
      # Default limit is 2× the interval implied by declared FPS.
      max_gap_multiplier: 2.0

  video.frozen_frames:
    options:
      max_consecutive_frames: 5
      # Action is preferred over noisier observed state by default.
      motion_streams: [action, observation.state]

  numeric.configured_bounds:
    options:
      limits:
        action:
          min: [-1.0, -1.0]
          max: [1.0, 1.0]

  numeric.discontinuity:
    options:
      max_delta:
        observation.state: [0.25, 0.25]

reports:
  json: true
  output_dir: .physlint/reports

Use it explicitly when needed:

physlint check /path/to/dataset --config physlint.yaml

Unknown top-level keys, rule IDs, rule options, duplicate required streams, and invalid values are rejected instead of silently ignored.

CI integration

The CLI has stable exit codes and writes reports atomically, so a basic GitHub Actions gate is small:

- name: Install Physlint
  run: python -m pip install "physlint[video]==0.1.0a1"

- name: Validate robot dataset
  run: |
    physlint check "$DATASET_PATH" \
      --json-output artifacts/physlint-report.json

- uses: actions/upload-artifact@v4
  if: always()
  with:
    name: physlint-report
    path: artifacts/physlint-report.json
Exit code Meaning
0 Validation completed and the configured contract passed
1 Validation completed and the contract failed
2 Invalid command or configuration
3 Dataset or adapter failure
4 Internal Physlint error
130 Interrupted by the user

Reproducible public-data evidence

The alpha release gate evaluates four immutable public snapshots from four producers:

Dataset Robot Episodes Frames Applicable rules Result
ViaCatalyst/robomimic-can-ph-lerobot-v3 Panda 10 1,160 11 Pass
cagataydev/scout-earth-rover-mini-20260616-053232 Earth Rover Mini 3 4,176 14 Pass
lerobot/svla_so101_pickplace SO-101 50 11,939 14 Pass
vikram-avea/sentinel-demo-09 YAM humanoid 11 13,983 14 Pass

Clean-source result: 4/4 snapshots pass with zero findings and zero rule errors. Controlled-defect recall: 3/3 for a non-finite value, reordered timestamps, and a deleted source row.

Everything needed to audit or rerun those claims is versioned:

Runtime measurements are observations from the documented machine and run—not universal performance guarantees.

Format roadmap

The storage format is an adapter boundary, not the product boundary.

Physlint format compatibility table: LeRobot v3 implemented and validated; MCAP with ROS 2 profiles and Robomimic planned; RLDS, TFDS, ROS bag2, and ROS 1 bag under research.
Format Status Intended mode
LeRobot Dataset v3.x Alpha—implemented and publicly validated Training datasets
MCAP with ROS 2 profiles Planned—seeking design partners Recordings and derived datasets
Robomimic HDF5 Planned Demonstration datasets
RLDS/TFDS Researching Episode/step datasets
ROS bag2 SQLite and ROS 1 bag Researching Recordings

MCAP needs two honest layers: container/channel health that works without training semantics, and an explicit profile mapping topics to actions, state, cameras, and episode boundaries. See the cross-format roadmap and MCAP/ROS proposal.

Use the adapter-request issue form to contribute an immutable public example and a real failure mode.

Current LeRobot boundary

Supported:

  • LeRobot v3.x meta/info.json schema and path templates
  • Chunked Parquet episode metadata and sample shards
  • Multiple episodes per shared Parquet/MP4 file
  • Fixed-size and regular vector features
  • Shared video segments using per-camera timestamp ranges
  • Metadata-first discovery and bounded batch iteration

Not currently supported:

  • LeRobot v2.0/v2.1
  • Remote Hub identifiers passed directly to physlint check
  • Image-directory features in the video rule set
  • Arbitrary codecs unavailable to the installed OpenCV build
  • Inferred safety, calibration, task-success, or coordinate-frame conclusions

Read the LeRobot adapter boundary.

Design principles

source format → read-only adapter → canonical episodes/streams → capability planner
                                                        ↓
                                           deterministic rule engine
                                                        ↓
                                      terminal + versioned JSON evidence
  • Read only: source datasets are never repaired or rewritten.
  • Lazy by default: metadata first, bounded Parquet batches, and one shared privacy-safe video analysis pass.
  • Explicit applicability: adapters advertise capabilities; unavailable checks explain why they did not run.
  • Stable evidence: rule versions, fingerprints, source revisions, and report schema are serialized.
  • Exception isolation: one rule failure cannot masquerade as a clean dataset pass.

Security and privacy

Validation is offline. Reports contain source references, timestamps, aggregate statistics, and targeted evidence—not embedded images or complete source samples. Treat every dataset parser as an attack surface and report suspected vulnerabilities privately through GitHub Security Advisories.

See SECURITY.md before submitting a vulnerability. Do not attach private datasets or sensitive reports to public issues.

Contributing

Contributions are welcome, particularly:

  • Public healthy and defective datasets for adapter release gates
  • False-positive reproductions
  • MCAP/ROS recording schemas and failure modes
  • New deterministic rules with controlled corruptions
  • Documentation, performance characterization, and privacy reviews

Development setup:

git clone https://github.com/pranayjoshi/physlint.git
cd physlint
python -m pip install -e ".[video,dev]"

ruff check .
ruff format --check .
mypy
pytest

Rules require positive and negative fixtures, stable remediation, a bounded finding count, and controlled corruption evidence where applicable. Adapters must remain read-only, metadata-first, lazy over samples, and explicit about capabilities.

Read CONTRIBUTING.md, open a format request, or join GitHub Discussions.

Project status

Physlint is an alpha. Its current claims are deliberately limited to the documented LeRobot v3 boundary and committed release evidence. The project does not train policies, repair data, host datasets, infer task success, produce an opaque quality score, or certify that a robot or policy is safe.

See CHANGELOG.md for release notes.

License

Physlint is available under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

physlint-0.1.0a1.tar.gz (998.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

physlint-0.1.0a1-py3-none-any.whl (40.2 kB view details)

Uploaded Python 3

File details

Details for the file physlint-0.1.0a1.tar.gz.

File metadata

  • Download URL: physlint-0.1.0a1.tar.gz
  • Upload date:
  • Size: 998.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for physlint-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 e7437d0ce55e2eb0f2c692970b67d440ad89cd440a1efe02f28c2b380fbbd7ac
MD5 5a11927541a3969f0bbf5cad0cad45a8
BLAKE2b-256 1835682dbccf898036e755ff157dae646d1bae99c0e1d72e2fb6706f9559b772

See more details on using hashes here.

Provenance

The following attestation bundles were made for physlint-0.1.0a1.tar.gz:

Publisher: publish.yml on pranayjoshi/physlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file physlint-0.1.0a1-py3-none-any.whl.

File metadata

  • Download URL: physlint-0.1.0a1-py3-none-any.whl
  • Upload date:
  • Size: 40.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for physlint-0.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 2ea9401c6c6bd8be70723e88b9b738ddd1ee8b81bdcb4e0ee2e3b33fa0fc2d1f
MD5 e8d750f94c2bdbb6d36f020c3e787522
BLAKE2b-256 de2f35d9ea2997a369daac24e461dc23efad6a94638b76de67c4234c31e2ee87

See more details on using hashes here.

Provenance

The following attestation bundles were made for physlint-0.1.0a1-py3-none-any.whl:

Publisher: publish.yml on pranayjoshi/physlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0a1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page