Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e9e37c4
docs: publish downloadable LEAPP integration skill
frlai Oct 14, 2026
59d2d35
docs: simplify skill banner and separate state from semantics
frlai Oct 14, 2026
465df4f
feat: add Rust bundle inspection API
malwan-nv Oct 14, 2026
4601c5f
feat: retain shared runtime lifecycle support
malwan-nv Oct 14, 2026
188f45c
feat: add Python bundle inspection bindings
malwan-nv Oct 14, 2026
2b281a0
feat: add C++ bundle inspection bindings
malwan-nv Oct 14, 2026
c6e70cb
Functionalize safe in-place tensor methods from ATen schemas (#28)
frlai Oct 16, 2026
c550e2d
merge: main into develop
frlai Oct 16, 2026
88bce07
Adopt Ruff formatting and enforce it in CI (#30)
frlai Oct 16, 2026
da03834
docs: clarify whole-pipeline export and optional stage boundaries (#29)
frlai Oct 17, 2026
698ea6c
docs: identify Isaac LEAPP and publish agent documentation index (#31)
frlai Oct 17, 2026
0e8b0ed
merge: main into develop
frlai Oct 19, 2026
3dbe6fc
docs: describe current bundle and lifecycle behavior
malwan-nv Oct 19, 2026
732d9a7
refactor: organize bundle inspection modules
malwan-nv Oct 19, 2026
7b88a73
refactor: remove custom YAML tag support
malwan-nv Oct 19, 2026
8ced418
feat: expose model input and output names
malwan-nv Oct 19, 2026
5f509b2
fix: preserve error chains and complete shutdown
malwan-nv Oct 19, 2026
c694c27
docs: use repository skill references in agent instructions
frlai Oct 19, 2026
ba891b3
docs: update Isaac Lab policy export URL (#38)
frlai Oct 20, 2026
656cc11
merge: main into develop
frlai Oct 20, 2026
1a749d3
Capture NumPy functions as ATen and support reverse slices (#32)
frlai Oct 21, 2026
1b92b41
test: organize bundle inspection tests
malwan-nv Oct 21, 2026
47bb35b
feat: expose the core Session API
malwan-nv Oct 21, 2026
1d055de
chore: merge develop into bundle API
malwan-nv Oct 21, 2026
5fb5cdd
refactor: align runtime API names and session options
malwan-nv Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ concurrency:
cancel-in-progress: true

jobs:
format:
name: Ruff formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Ruff
run: python -m pip install ruff==0.17.1
- name: Check formatting
run: ruff format --check .

test:
runs-on: [self-hosted, gpu]
container:
Expand Down
58 changes: 52 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@ Python 3.10+ and PyTorch 2.6.0+. Visualization extras install only on

## Load this first

All instruction and skill references below are relative to the repository
root and tracked in Git. Do not require machine-local or editor-specific
skill installations.

| If you are changing… | Read this before editing |
|---|---|
| Tracing, `TracedData` / `TracedTensor` / `TracedNpArray`, indexing, mutation, node-boundary identity, FX proxies, NumPy dispatch | `.cursor/skills/leap_agent/SKILL.md` |
| Warp tracing (`TracedWpArray`, APIC, `warp_op`) | `warp_support.md` |
| Tracing, `TracedData` / `TracedTensor` / `TracedNpArray`, indexing, mutation, node-boundary identity, FX proxies, NumPy dispatch | [SKILL.md](SKILL.md), especially "Preserve graph connections and computation" and "Diagnose trace loss before changing exporters"; implementation in `leapp/leapp_graph/` |
| Warp tracing (`TracedWpArray`, APIC, `warp_op`) | [Warp guide](references/warp.md) |
| Public annotate/lifecycle API or docs examples | `docs/source/api/index.rst` plus the matching guide under `docs/source/` |
| Graph PNG layout | `packages/leapp-visualization/` |
| Export backends | `leapp/backends/` |
| YAML / `InferenceManager` | `leapp/leapp.py` (`compile_graph`), `leapp/inference_manager.py`, `docs/source/generated_configs.rst` |

Do not mix the skill's current `(context_obj, output_port)` identity with
legacy `leapp_tag` helpers. The skill states which checkout you have.
Do not mix the current `(context_obj, output_port)` identity with
legacy `leapp_tag` helpers. Check the implementation in this repository
when changing tracing internals.

## Tree (start here)

Expand Down Expand Up @@ -72,7 +77,35 @@ Narrower (use these while iterating):
| Annotate / I/O / state | `pytest tests/functional_tests/ -v` |
| Examples | `pytest tests/test_examples/ -v` |
| Visualization | `pytest packages/leapp-visualization/tests/ -v` (Python 3.11+) |
| Warp tracing | see `warp_support.md` |
| Warp tracing | see [Warp guide](references/warp.md) |

### Python formatting

Use Ruff for Python formatting. The pinned development dependency and
`[tool.ruff]` configuration in `pyproject.toml` set an 88-character line width
and Python 3.10 compatibility. Run these commands from the repository root
after editing Python code and before handing off changes:

```bash
ruff format .
ruff format --check .
```

This covers the main package, visualization package, tests, Python
docs configuration, and `scripts/leapp-build-warp-runtime`. The separate
`Ruff formatting` CI job runs `ruff format --check .` on pull requests and
fails if formatting changes are needed. No local Git hook is required.

The entire `examples/` directory is excluded from Ruff formatting, including
when example files are passed explicitly. Preserve their existing layout.
When editing examples, check documentation excerpts and source links; prefer
function names or text boundaries over fixed line ranges.

Use the pinned Ruff version instead of Black. Formatting does not include
lint fixes or import sorting; keep those changes out of formatting-only work.
When upgrading Ruff, update the dependency and `required-version` in
`pyproject.toml`, the install pin in `.github/workflows/ci.yml`, and `uv.lock`
together.

### Warp runtime build

Expand Down Expand Up @@ -151,6 +184,19 @@ User-facing integration recipes belong here, not in this file.

## Guardrails when changing behavior

- Tracing can enter branches that are not needed to produce the declared
outputs. Report recoverable capture or translation failures with
`_get_logger().error(...)`, which logs without raising; do not abort the
entire trace merely because such a branch cannot be captured. Keep this
distinction from `_get_logger().fatal(...)`, which raises. Test that an
unsupported operation on an unused branch does not prevent exporting the
supported output graph. Preserve failed-operation dependencies until output
pruning, and reject export if a declared output depends on a failed capture;
test direct and downstream dependencies separately.
- NumPy capture checks graph structure and mutation safety. Leave numerical
comparisons to final exported-node validation; do not add per-call eager
parity checks to the adapter. Retain shape, dtype, value, and changed-input
parity coverage in tests, including final validation rejecting wrong outputs.
- Prefer extending `TracedData` once (`_map_structure`, index lowering,
port preserve/clear) over copying logic into tensor, NumPy, and Warp
classes. Warp value semantics live on `TracedWpArray`; `WarpPatchBackend`
Expand All @@ -159,7 +205,7 @@ User-facing integration recipes belong here, not in this file.
lifecycle stays in `warp/session.py`, `warp_op.py`, and
`warp/warp_segment.py`.
- After shared indexing changes: both torch and NumPy unit suites, plus
FX / jit / exported-program coverage as the skill describes.
FX / jit / exported-program coverage in `tests/`.
`onnx-dynamo` for modern index cases; do not require legacy ONNX if
that exporter cannot lower the op.
- Do not invent graph edges for data a node did not publish. Clearing
Expand Down
25 changes: 24 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
#### Formatting

LEAPP uses Ruff for Python formatting, with an 88-character line width. Install
the development dependencies and run the formatter from the repository root:

```bash
python -m pip install -e ".[dev]"
ruff format .
ruff format --check .
```

The separate `Ruff formatting` CI job checks pull requests and fails if files
need formatting. Run `ruff format .` locally and include the resulting changes
in your PR. No local Git hook is required. You can also enable format on save
with the Ruff editor extension.

The `examples/` directory is excluded from formatting to preserve the examples'
existing layout, including when files are passed explicitly to Ruff.

Keep the Ruff version in `pyproject.toml` and `.github/workflows/ci.yml` in sync
and regenerate `uv.lock` when upgrading. Formatting does not run lint fixes or
sort imports.

#### Signing Your Work

* We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
Expand Down Expand Up @@ -53,4 +76,4 @@ SPDX-License-Identifier: Apache-2.0
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
this project or the open source license(s) involved.
57 changes: 37 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,67 @@ SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All
SPDX-License-Identifier: Apache-2.0
-->

# LEAPP — Lightweight Export Annotations for Policy Pipelines
# LEAPP: Lightweight Export Annotations for Policy Pipelines

LEAPP is a Python package for tracing and exporting multi-step PyTorch computational graphs. Annotate your existing code with lightweight markers, and LEAPP captures the graph structure, exports each stage as an individual model, and generates a deployment-ready YAML specification.
[Full Isaac LEAPP docs](https://nvidia-isaac.github.io/leapp/)

LEAPP is designed for pipelines that chain multiple PyTorch models or processing stages together — where you need to export the whole pipeline, not just a single model. It traces real execution of your code, records which tensors flow between stages, exports each stage independently, and writes a YAML that describes how to wire everything back together at inference time.
**Export the policy code you already run: preprocessing, model inference, and action processing together.**

## Installation
Isaac LEAPP is NVIDIA's library for machine learning pipeline export. It traces supported PyTorch and NumPy computation across existing functions and objects. Export the complete path as **one ONNX, TorchScript, or PT2 model**, or choose separate stages when useful.

Input and output annotations capture computation as your application runs. A single model can capture computation across multiple input call sites, helper functions, and class methods. The annotations work directly in application code without a prescribed RL environment interface. [See annotation patterns](https://nvidia-isaac.github.io/leapp/guides/nodes.html).

- **Keep processing with the policy.** Capture supported NumPy preprocessing, conversions into PyTorch, and action transforms together. [Warp kernel regions](https://nvidia-isaac.github.io/leapp/tensor_libraries/warp.html) can also be captured into ONNX or PT2 with an additional runtime adapter.
- **Adapt unsupported calls with [FunctionPatch](https://nvidia-isaac.github.io/leapp/guides/patching.html).** Register a faithful replacement built from supported operations; existing module-level callers can stay in place.
- **Describe the deployment interface.** Attach tensor roles, joint names, and timing information with [semantic metadata](https://nvidia-isaac.github.io/leapp/semantics/usage.html), so downstream applications can interpret model inputs and outputs.
- **Inspect and validate the export.** Compare exported outputs, including state updates, against cached samples from consecutive Python iterations. Configure sample coverage, inspect the graph, and use [sequential replay](https://nvidia-isaac.github.io/leapp/guides/debugging.html#stateful-transitions-and-sequential-replay) to check accumulated drift and runtime feedback.

## Quick start

```bash
pip install leapp
```

LEAPP requires Python 3.10+ and PyTorch 2.6.0+.
Requires Python 3.10+ and PyTorch 2.6.0+.

## Quick example
This example exports NumPy preprocessing, a small PyTorch policy, and action scaling and clipping together:

```python
import numpy as np
import torch
import leapp
from leapp import annotate

leapp.start(name="my_pipeline")
def make_observation(position, velocity):
return np.concatenate([np.clip(position, -1.0, 1.0), velocity * 0.1])

policy = torch.nn.Sequential(
torch.nn.Linear(12, 32), torch.nn.Tanh(), torch.nn.Linear(32, 6),
).eval()

leapp.start(name="robot_policy")
position, velocity = annotate.input_tensors("control", {
"position": np.zeros(6, dtype=np.float32),
"velocity": np.ones(6, dtype=np.float32),
})

x = annotate.input_tensors("preprocess", {"obs": torch.randn(8)})
features = (x - x.mean()) / (x.std() + 1e-6)
annotate.output_tensors("preprocess", {"features": features}, export_with="jit")
with torch.no_grad():
observation = torch.from_numpy(make_observation(position, velocity))
targets = torch.clamp(policy(observation) * 0.25, -1.0, 1.0)

features = annotate.input_tensors("policy", {"features": features})
action = torch.tanh(features @ torch.randn(8, 4))
annotate.output_tensors("policy", {"action": action}, export_with="onnx")
annotate.output_tensors("control", {"targets": targets}, export_with="onnx")

leapp.stop()
leapp.compile_graph()
leapp.compile_graph(validate=True)
```

Running this produces a `my_pipeline/` directory containing the exported models, a YAML pipeline spec, and, on Python 3.11 or later, a PNG graph visualization. On Python 3.10, LEAPP warns and skips visualization while completing the rest of the export.
Produces **`robot_policy/control.onnx`**, a YAML interface specification, and a graph PNG on Python 3.11+. This stateless model runs directly in ONNX Runtime; [InferenceManager](https://nvidia-isaac.github.io/leapp/leapp_runtime.html) loads the bundle for Python replay. Other applications can consume the exported artifacts through their chosen backend runtime.

## Documentation
## Capture scope

Full guides and API reference live at **[https://nvidia-isaac.github.io/leapp/](https://nvidia-isaac.github.io/leapp/)**:
LEAPP captures the executed tensor path. Data-dependent Python branches are not preserved dynamically, and unsupported operations or scalar extraction can freeze values. Check tracing warnings and validate on fresh inputs. See [PyTorch](https://nvidia-isaac.github.io/leapp/tensor_libraries/torch_limitations.html) and [NumPy](https://nvidia-isaac.github.io/leapp/tensor_libraries/limitations.html) limitations.

- [Getting started](https://nvidia-isaac.github.io/leapp/getting_started.html) — install, first pipeline, generated output
- [Guides](https://nvidia-isaac.github.io/leapp/guides/index.html) — node patterns, export options, feedback graphs, semantic data, runtime validation
- [API reference](https://nvidia-isaac.github.io/leapp/api/index.html)
[Getting started](https://nvidia-isaac.github.io/leapp/getting_started.html) · [Export options](https://nvidia-isaac.github.io/leapp/guides/export.html) · [API reference](https://nvidia-isaac.github.io/leapp/api/index.html)

## License

Expand Down
9 changes: 6 additions & 3 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ Calls in NumPy, SciPy, scikit-learn, scikit-image, OpenCV, or other libraries **

| Hazard | What the agent should do |
|--------|--------------------------|
| Unmapped NumPy/native operation | Treat the trace warning as a correctness failure. A plain result mixed back into traced data can become a constant. Patch the operation and compare new inputs against the original. |
| Unsupported NumPy/native operation | NumPy capture checks graph structure; numerical comparison happens during final exported-node validation. Recoverable capture failures log errors and continue eager execution. Unused failures are pruned; a failed dependency in the declared output graph blocks export. Unsupported mutations remain immediate errors. Calls that bypass the hooks can still return plain values that become constants. Patch unsupported computation and compare new inputs against the original. |
| `.item()`, `.tolist()`, `float()`, `int()` | Audit explicitly: Torch extraction can be silent. Keep dynamic data in traced operations; logs alone cannot prove correctness. |
| NumPy indexing down to a scalar or NumPy scalar operands | Check for loss of array tracing or unsupported operand types. Use a faithful adapter preserving the needed array computation. |
| NumPy negative-stride slicing, unsupported `astype` dtype | Eager and exported behavior can disagree. Check the online limitations and implement supported equivalent operations within the adapter. |
| NumPy indexing down to a scalar | Keep an array dimension to preserve runtime dependence. Constant NumPy scalar operands are accepted, but cannot restore a dependency lost by indexing. |
| NumPy negative-stride slicing | Static basic reads use `flip` or normalized indices with `index_select`. Runtime bounds, mixed advanced indices, reverse assignment, and mutation through reversed views need separate support. |
| Unsupported `astype` dtype | Eager and exported dtypes can disagree. Use a supported dtype and check replay against the original. |
| Tensor-dependent Python `if`/`while` or iteration counts | Only the executed path is captured. Use a faithful traceable expression in an adapter where possible; otherwise document the supported domain or external control-flow boundary. Another exporter cannot recover a branch already lost. |

Supported NumPy/Torch conversions such as `torch.from_numpy()` and `.numpy()` can preserve tracing with global patching enabled. Do not rewrite all NumPy code or treat every conversion as a trace break.
Expand All @@ -180,6 +181,8 @@ Warp is part of this skill. **Before integrating Warp, read [the complete Warp g

## Validate the whole exported pipeline

`compile_graph(validate=True)` compares all cached node outputs, including exported state updates. Consecutive samples validate the original pipeline's stateful transitions, not just its actions. Each sample supplies recorded reference inputs/state; sequential runtime replay instead feeds exported state forward and checks accumulated numerical drift and runtime feedback/reset handling. Cache size controls transition coverage, not feedback replay. See [stateful validation](https://nvidia-isaac.github.io/leapp/guides/debugging.html#stateful-transitions-and-sequential-replay).

1. Compare the original application and annotated execution using the same inputs, weights, state, execution mode, and random seeds where relevant. Check function adapters against original functions separately.
2. Run `compile_graph(validate=True, strict=True)` with justified tolerances. Inspect warnings and generated YAML: expected external inputs, final outputs, forward/feedback edges, initial values, backend types, and existing artifact paths. Explain any unexpected dangling input.
3. Load the bundle with `InferenceManager` and compare **fresh representative inputs not used during tracing** against the original pipeline. A mock-input smoke test alone is insufficient. Include realistic value ranges and relevant branches/shapes; for stateful pipelines compare a sequence from matching initial/reset state.
Expand Down
4 changes: 2 additions & 2 deletions docs/source/_static/images/getting_started_graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions docs/source/_templates/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{#
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
#}
{% extends "!layout.html" %}

{% block extrahead %}
{{ super() }}
<link rel="describedby" type="text/plain" href="{{ pathto('llms.txt', 1) }}">
{% if pagename == 'index' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"@id": "https://nvidia-isaac.github.io/leapp/#software",
"name": "Isaac LEAPP",
"alternateName": ["LEAPP", "Lightweight Export Annotations for Policy Pipelines"],
"description": "Isaac LEAPP is NVIDIA's library for machine learning pipeline export. Capture supported preprocessing, inference, and postprocessing in ONNX, TorchScript, or PT2 models.",
"applicationCategory": "DeveloperApplication",
"applicationSubCategory": "Machine learning pipeline export",
"url": "https://nvidia-isaac.github.io/leapp/",
"sameAs": ["https://github.com/nvidia-isaac/leapp", "https://pypi.org/project/leapp/"],
"publisher": {
"@type": "Organization",
"name": "NVIDIA",
"url": "https://www.nvidia.com/"
},
"license": "https://www.apache.org/licenses/LICENSE-2.0"
}
</script>
{% endif %}
{% endblock %}
Loading
Loading