AGPL to Permissive License Migration on Jetson TensorRT
When a Jetson-based perception stack ships to a paying customer, the license graph underneath the model weights matters as much as the inference architecture on top of it. We recently ran an AGPL to permissive license migration on a client’s TensorRT pipeline: an open-vocabulary detector, an instance segmenter, and a depth model, prototyped fast on licenses that would not have cleared for a commercial deliverable as-is. The fix was not a rewrite. It was a capability map, a checkpoint audit, and one gotcha that would have re-tainted the whole deliverable if we had missed it: a model whose code is Apache-2.0 but whose default checkpoint is not.
Key Insights
- AGPL-3.0’s network-use clause reaches any service that talks to a user over a socket. A single AGPL import in a Jetson inference pipeline can put the commercial license of the entire deliverable at risk, not just that one component.
- Treat the migration as a capability swap, not a package swap. A monolithic AGPL-3.0 vision library (in this case bundling YOLO-World for open-vocabulary detection and FastSAM for instance segmentation) hides several distinct capabilities behind one import; decompose first, then replace each one.
- Code license and weights license are not the same thing. Depth-Anything-V2’s code is Apache-2.0, but only the Small checkpoint carries that license. The Base and Large checkpoints are CC-BY-NC and will re-taint a commercial product if a config file ever points at them.
- Freeze the public interface of every model wrapper before touching the implementation. When
Detector.detect()andSegmenter.segment()keep the same signature, the orchestrator, the ROS 2 node, the tracker, and the overlay code never have to change. - A permissive fallback path is worth more than raw throughput. When our optimized TensorRT segmentation path broke at export time, we dropped to plain PyTorch for that one model and still shipped roughly 4x faster end to end than the original AGPL baseline, because the detector stayed TensorRT-native.
What Is AGPL to Permissive License Migration and Why Does It Matter on Jetson?
AGPL-3.0 differs from plain GPL in one clause that catches most engineering teams off guard: Section 13, the network-use clause. Regular GPL triggers on distributing a binary. AGPL triggers on letting a user interact with the software over a network, whether or not you ever hand them a copy of it. A Jetson device that runs inference and answers a request, whether that request comes from a companion app, a REST call from a fleet manager, or another service on the same LAN, counts as that kind of interaction. Ship a modified AGPL-3.0 model in that path and you can trigger an obligation to offer the corresponding source, including your own glue code around the model.
For a client who owns a proprietary, closed-source product, that is not a negotiable licensing cost. It is disqualifying. The stack we inherited used a single AGPL-3.0 vision library for two jobs at once: an open-vocabulary detector (YOLO-World) and an instance segmenter (FastSAM). Both are capable models. Neither is licensable into a client-owned commercial deliverable without a paid Ultralytics Enterprise license.
The mistake teams make here is treating the fix as “find a permissive alternative to library X.” That framing sends people looking for a single drop-in replacement that does not exist. The library was never one thing; it bundled two capabilities behind one import, plus a third that had not been added yet (monocular depth). Once we reframed the task as a capability inventory, the migration stopped being a research problem and became a mechanical one.
The AGPL to Permissive License Migration Capability Map
Once you decompose the AGPL package into distinct capabilities, each one gets its own permissive replacement, and some capabilities may already be clean. Here is the map we built for this stack:
| Capability | AGPL-3.0 incumbent | Permissive replacement | License |
|---|---|---|---|
| Open-vocabulary detection | YOLO-World | NanoOWL / OWL-ViT | Apache-2.0 |
| Instance segmentation | FastSAM | NanoSAM, or upstream MobileSAM | Apache-2.0 |
| Monocular depth | (new capability) | Depth-Anything-V2-Small | Apache-2.0* |
| Multi-object tracking | (already separate) | supervision / ByteTrack | MIT |
| PyTorch to TensorRT conversion | (already separate) | torch2trt | MIT |
| Weights and text/image encoders | (already separate) | HuggingFace transformers | Apache-2.0 |
*See the checkpoint trap below; the Apache-2.0 grant does not cover every checkpoint in this repo.
Tracking was already MIT before we touched anything. We verified it and left it alone. Half the value of building this table is knowing which capabilities do not need to move, so you do not spend engineering time re-validating a component that was never the problem.
The Checkpoint License Trap: Apache-2.0 Code, Non-Commercial Weights
This is the part almost nobody checks, and it is the reason this migration is worth writing up. A repository’s code license is not automatically the license of the model weights it publishes. Depth-Anything-V2 ships its code under Apache-2.0. Its Small checkpoint is Apache-2.0 too. Its Base and Large checkpoints, the ones with the best accuracy and the ones a benchmark table will point you toward, are released under CC-BY-NC, a non-commercial license. Load the Base checkpoint into an otherwise clean Apache-2.0 codebase and you have re-introduced the exact problem you spent the migration solving, just one layer down, in the weights instead of the code.
We pin the exact checkpoint name in config, not just the model family:
models:
depth:
enabled: false
name: depth-anything-v2-small # SMALL only, Base/Large are CC-BY-NC
backend: tensorrt
A comment in a YAML file will not survive config edits by someone who was not in the room for this decision, so we enforce it in code:
_APACHE_OK = {"depth-anything-v2-small"} # Base/Large are CC-BY-NC
def __init__(self, cfg):
if cfg.name not in _APACHE_OK:
raise ValueError(
f"{cfg.name!r} is not an Apache-2.0 checkpoint; "
f"only {sorted(_APACHE_OK)} may ship commercially"
)
The wrapper raises before the model even loads if someone points the config at a non-commercial checkpoint. That single check is cheap insurance against a future fine-tune or a well-meaning teammate chasing an accuracy number, silently reintroducing a license problem that a code review would probably not catch, because the diff looks like a one-line config change.
Freezing Wrapper Interfaces to Contain the Blast Radius
The reason this kind of migration is cheap instead of a rewrite is that every model lives behind a thin wrapper class, and we freeze the public interface of that wrapper before changing anything inside it.
| Wrapper | Frozen public surface | What changes inside |
|---|---|---|
Detector | set_classes(prompts), detect(frame) -> list[Detection], .active_classes | Constructor and implementation now wrap OwlPredictor instead of the AGPL detector |
Segmenter | segment(frame, boxes) -> list[mask] | Constructor and implementation now wrap MobileSAM instead of FastSAM |
Because those method signatures and the Detection dataclass never move, the orchestrator, the ROS 2 node, the overlay renderer, and the tracker do not need to change at all. The entire change set collapses to five things: the two wrapper implementations, their tests, the config schema (new fields for engine paths, checkpoint names, thresholds), the Dockerfile, and asset provisioning for the new engines. The one caller-side change we could not avoid was the constructor call site, since the new wrappers take a config object instead of unpacked positional arguments; we isolated that to a single line in the node.
We also make the license reasoning visible right where dependencies enter the container image, so a future audit does not have to reconstruct the decision from memory:
# ultralytics removed, AGPL-3.0. supervision (ByteTrack) is MIT, transformers is Apache-2.0.
RUN python3 -m pip install --no-cache-dir --no-deps \
supervision==0.24.0 defusedxml==0.7.1 \
&& python3 -m pip install --no-cache-dir transformers
# NanoOWL (Apache-2.0), detection.
RUN git clone --depth 1 https://github.com/NVIDIA-AI-IOT/nanoowl /opt/nanoowl \
&& cd /opt/nanoowl && python3 setup.py develop
# Upstream MobileSAM (Apache-2.0). --no-deps preserves the platform CUDA torch.
RUN python3 -m pip install --no-cache-dir --no-deps \
git+https://github.com/ChaoningZhang/MobileSAM.git timm
--no-deps matters for two reasons on an accelerator platform. It stops pip from silently pulling a transitive AGPL dependency back in, and it stops pip from overwriting the vendor-built CUDA-enabled torch with a stock PyPI wheel that does not know your GPU exists. Audit the transitive closure, not just the direct import; the AGPL package is only gone once nothing underneath it is AGPL either.
When the Optimized TensorRT Path Breaks, Keep the Permissive Fallback
The cleanest replacement on paper does not always survive the target toolchain, and that is where the license decision has to hold independently of the performance plan. Our first choice for the segmentation swap was to run MobileSAM through TensorRT for the mask decoder. It did not survive contact with the hardware: the vendor-published ONNX assets for that decoder were dead links, and the version we exported locally contained a shape-computation op that the target TensorRT release rejected outright.
Because we had picked an Apache-2.0 replacement rather than the cheapest replacement, the fallback was simple: run that same MobileSAM segmenter in plain PyTorch instead of TensorRT. The license held. Only the performance plan changed. End-to-end throughput still landed at roughly 4x the original AGPL PyTorch baseline, because the detector stayed TensorRT-native and dominated the wall-clock budget; the segmenter running unoptimized cost us some headroom, not the deliverable.
The lesson generalizes past this one project: pick a replacement whose permissive license still holds in its slowest, least-optimized execution mode. A toolchain block should cost you throughput. It should never cost you the license.
If you are running this same class of migration, the checklist we use every time is short:
- Identify every AGPL import and the discrete capabilities each one provides.
- Map each capability to an Apache-2.0 or MIT replacement, and confirm which capabilities were already clean so you do not touch them.
- Audit both the code license and the per-checkpoint or per-weights license for every replacement; pin the exact commercial-safe variant by name.
- Freeze wrapper public interfaces; contain the change to wrapper internals, tests, config schema, the Dockerfile, and asset provisioning.
- Encode the license reasoning at the dependency boundary and install with
--no-depswhere relevant; verify the transitive closure is AGPL-free. - Enforce the checkpoint or weights license in code so a future config edit cannot silently regress it.
- Confirm the replacement’s license still holds in any degraded or fallback execution path before you commit to that replacement.
We ran this same detection, segmentation, and depth stack on the real-time perception demo we built on Jetson. If you are deciding where to spend optimization budget once the licensing is settled, our TensorRT vs DLA comparison on Jetson Orin covers GPU-versus-DLA placement for whichever of these models you end up optimizing.
Frequently Asked Questions
Is YOLO-World free to use in a commercial product?
Not without a separate commercial license. YOLO-World ships as part of the Ultralytics package under AGPL-3.0, which means any product that lets a user interact with it over a network, including an on-device API on a customer-owned appliance, can trigger source-disclosure obligations. Ultralytics sells an Enterprise license specifically to cover this case.
Does AGPL apply to a Jetson device that never touches the public internet?
Yes, in most practical cases. The AGPL network-use clause is not limited to the public internet; it covers any network interaction where a user sends the modified program a request and receives a response, including a LAN-only API or a companion app talking to the device locally. Shipping the device itself to a customer is also a form of conveyance under GPL-family licenses, independent of the network clause.
Is Depth-Anything-V2 free for commercial use?
Only the Small checkpoint. The code repository is Apache-2.0 across the board, but the Base and Large checkpoints are released under CC-BY-NC, a non-commercial license, separate from the code license. Pin the checkpoint name explicitly in config and enforce it in code, since a benchmark table will usually point you toward Base or Large for accuracy, not Small.
What license are NanoOWL and NanoSAM released under?
Both are Apache-2.0, published by NVIDIA-AI-IOT as Jetson-optimized ports of open-vocabulary detection (NanoOWL, built on OWL-ViT) and segmentation (NanoSAM). They are common permissive replacements for YOLO-World and FastSAM in exactly this kind of migration.
Do I need a lawyer to do an AGPL to permissive license migration?
Get legal sign-off before you ship, but the bulk of the work is engineering: building the capability map, auditing per-checkpoint licenses, and freezing wrapper interfaces. Doing that work first turns an open-ended legal review into a short table your counsel can confirm in an afternoon instead of an audit that stalls the release.
ProventusNova helps hardware startups solve embedded systems problems fast. If your Jetson perception stack needs an AGPL to permissive license audit before it can ship to a customer, see our edge AI deployment services.
Relevant Services
NVIDIA Jetson Expert Support
Stuck on a Jetson bring-up?
We've debugged this failure mode before. BSP, device tree, camera pipelines, OTA, most blockers clear in the first session. No long retainers. No guessing.
Frequently Asked Questions
Is YOLO-World free to use in a commercial product?
Not without a separate commercial license. YOLO-World ships as part of the Ultralytics package under AGPL-3.0, which means any product that lets a user interact with it over a network, including an on-device API on a customer-owned appliance, can trigger source-disclosure obligations. Ultralytics sells an Enterprise license specifically to cover this case.
Does AGPL apply to a Jetson device that never touches the public internet?
Yes, in most practical cases. The AGPL network-use clause is not limited to the public internet; it covers any network interaction where a user sends the modified program a request and receives a response, including a LAN-only API or a companion app talking to the device locally. Shipping the device itself to a customer is also a form of conveyance under GPL-family licenses, independent of the network clause.
Is Depth-Anything-V2 free for commercial use?
Only the Small checkpoint. The code repository is Apache-2.0 across the board, but the Base and Large checkpoints are released under CC-BY-NC, a non-commercial license, separate from the code license. Pin the checkpoint name explicitly in config and enforce it in code, since a benchmark table will usually point you toward Base or Large for accuracy, not Small.
What license are NanoOWL and NanoSAM released under?
Both are Apache-2.0, published by NVIDIA-AI-IOT as Jetson-optimized ports of open-vocabulary detection (NanoOWL, built on OWL-ViT) and segmentation (NanoSAM). They are common permissive replacements for YOLO-World and FastSAM in exactly this kind of migration.
Do I need a lawyer to do an AGPL to permissive license migration?
Get legal sign-off before you ship, but the bulk of the work is engineering: building the capability map, auditing per-checkpoint licenses, and freezing wrapper interfaces. Doing that work first turns an open-ended legal review into a short table your counsel can confirm in an afternoon instead of an audit that stalls the release.
Written by
Andrés CamposCo-Founder & CTO · ProventusNova
8 years deep in embedded systems, from underwater ROVs to edge AI. Andrés leads every technical delivery personally.
Connect on LinkedInRelated Articles
JetPack versions and L4T compatibility: complete reference table
Complete JetPack version to L4T, CUDA, TensorRT, and supported module reference table. Includes how to check your running version and key differences.
OpenCV with CUDA on Jetson: CUDA_ARCH_BIN, cmake flags, JetPack 5 and 6
Install OpenCV with CUDA on Jetson from source. cmake flags, CUDA_ARCH_BIN per module, swap setup, JetPack 5 and 6 differences, and troubleshooting.
Python to C++: 4x Latency Reduction on Jetson
Python to C++ on Jetson: 4x latency cut via GStreamer + TensorRT. Profiler output, NVMM buffer path, and the exact changes that took 280ms to 68ms.
Real-Time Perception on the Edge: Detection, Segmentation, and Depth
A modular edge perception pipeline: open-vocabulary detection, instance segmentation, and depth estimation running locally with live metrics. No cloud.