play_launch
Resolve, run, and analyze ROS 2 launch executions with resource monitoring and interactive management.
Upgrading? CHANGELOG.md lists the breaking changes — 0.9.0 has several, and a few of them change behaviour rather than erroring.
Installation
Requires Ubuntu 22.04+ with ROS 2 (Humble or Jazzy), Python 3.10+, and:
sudo apt install libz3-dev
sudo apt install ros-${ROS_DISTRO}-rclcpp-components ros-${ROS_DISTRO}-class-loader
Install from PyPI:
pip install play_launch
This installs the play_launch command, which carries the whole surface:
launch, run, up, resolve, dump, check, plot, contract,
context, setcap, verify.
Optional: grant the helper binaries the capabilities they need for per-process I/O monitoring and non-root RT scheduling (requires sudo):
play_launch setcap
This enables per-process I/O monitoring and non-root RT scheduling (
--sched):play_launch setcapgrantsCAP_SYS_PTRACEto the I/O helper andCAP_SYS_NICEto the RT helper — both are small ROS-free binaries. The mainplay_launchbinary is never given a file capability — that would put it in secure-execution mode and stop it finding its ROS libraries.See the Real-Time Scheduling Guide for the scheduling spec format and how it maps onto processes, threads, and the kernel.
Quick Start
Launch any ROS 2 package with monitoring and Web UI enabled by default:
play_launch launch demo_nodes_cpp topics/talker_listener.launch.py
Access Web UI at http://127.0.0.1:8080 for real-time node management and log streaming.
The Rust parser is used by default for speed. For maximum compatibility, use --parser python.
Usage
Launch Files
Replace ros2 launch with play_launch launch:
play_launch launch <package> <launch_file> [arguments...]
Single Nodes
Replace ros2 run with play_launch run:
play_launch run <package> <executable> [arguments...]
Two-Step Workflow
Resolve once, bring the system up as often as you like:
# Resolve once — writes system_model.yaml
play_launch dump launch <package> <launch_file> [arguments...]
# Bring it up, as often as you like
play_launch up system_model.yaml
up takes the model path positionally or as --model <path>; it is required
either way, since the model is the only thing up spawns from.
Checking Contracts
check parses a launch file and checks the contracts shipped beside it
(<stem>.contract.yaml). It needs no ROS graph and is meant for CI:
play_launch check my_pkg bringup.launch.xml # 0 clean, 1 errors, 3 a contract refused
play_launch check bringup.launch.xml --expect ladder-rung-budget # a negative test
play_launch check bringup.launch.xml --explain --width 100 # the fault-reaction table, wrapped
play_launch --version # play_launch 0.13.0 (v0.13.0-9-gabc1234, rlm v0.1.47)
Exit status 3 means a contract file did not parse (error[manifest-parse]),
so it was not checked at all; the refusal names the checker's version and the
grammar (rlm tag) it reads. Through a pipe the output is ASCII without colour
(NO_COLOR is honoured on a terminal too). Exit codes, --expect, the JSON
report and the --explain table: Checking contracts in CI.
Features
All features enabled by default:
- Resource monitoring: CPU, memory, I/O, GPU (2s interval)
- Diagnostic monitoring: the
/diagnosticstopic (add more viadiagnostics.topics) - Web UI: Interactive management at
http://127.0.0.1:8080 - Container isolation: Composable nodes run in isolated processes via fork+exec (default)
Disable Features
Disable specific features:
play_launch launch <package> <launch_file> --disable-monitoring
play_launch launch <package> <launch_file> --disable-diagnostics
play_launch launch <package> <launch_file> --disable-web-ui
play_launch launch <package> <launch_file> --disable-all
Container Mode
Control how composable nodes are managed (default: isolated):
# Isolated: fork+exec per-node process isolation (default)
play_launch launch <pkg> <file> --container-mode isolated
# Observable: ComponentEvent publishing, shared process
play_launch launch <pkg> <file> --container-mode observable
# Stock: use original container from launch file, no override
play_launch launch <pkg> <file> --container-mode stock
Adjust Monitoring
Change sampling interval (default: 2000ms):
play_launch launch <package> <launch_file> --monitor-interval-ms 500
Configure Web UI
Change address or port (default: 127.0.0.1:8080):
play_launch launch <package> <launch_file> --web-addr 0.0.0.0:8080
Configuration File
Use YAML for advanced control:
# config.yaml
monitoring:
enabled: true
sample_interval_ms: 2000
processes:
- node_pattern: "NODE 'rclcpp_components/component_container*"
cpu_affinity: [0, 1]
nice: 5
Apply configuration:
play_launch launch <package> <launch_file> --config config.yaml
play_launch up system_model.yaml --config config.yaml
Visualization
Generate interactive plots from monitoring data:
# Plot latest execution
play_launch plot
# Plot specific log directory
play_launch plot --log-dir play_log/2025-10-28_16-17-56
# Plot specific metrics
play_launch plot --metrics cpu --metrics memory
# List available metrics
play_launch plot --list-metrics
Output saved to play_log/<timestamp>/plot/:
cpu_timeline.html- CPU usage over timememory_timeline.html- Memory usage over timeio_timeline.html- I/O read/write ratescpu_distribution.html- CPU distribution box plotmemory_distribution.html- Memory distribution box plotstatistics.txt- Top 10 rankings for all metrics
Web UI Features
- Node management: Start/Stop/Restart individual or all nodes
- Container controls: Load/Unload composable nodes
- Real-time logs: Stream stdout/stderr with log level coloring and filtering
- Diagnostics panel: View
/diagnosticsmessages with level filtering - Status monitoring: Color-coded node states
- Auto-restart: Per-node automatic restart configuration
- Search & filter: Find nodes in large deployments
Output Structure
play_log/<timestamp>/
├── node/<node_name>/
│ ├── metadata.json
│ ├── metrics.csv # Resource metrics (when enabled)
│ ├── out/err # Process logs
│ ├── pid/status/cmdline
│ └── params_files/ # ROS parameter files
├── load_node/<name>/
│ └── out/err # Per-composable-node logs (isolated mode)
├── system_stats.csv # System-wide metrics
├── diagnostics.csv # Diagnostic messages (when enabled)
└── plot/ # Generated visualizations
Command Reference
# Launch (all features enabled by default)
play_launch launch <package> <launch_file> [args...]
play_launch run <package> <executable> [args...]
# Dump and up (dump emits the SystemModel by default — one artifact)
play_launch dump launch <package> <launch_file> [args...]
play_launch up system_model.yaml # or: play_launch up --model system_model.yaml
# Parser selection (Rust is default)
play_launch launch <pkg> <file> --parser rust # Default, fast
play_launch launch <pkg> <file> --parser python # Maximum compatibility
# Container mode
play_launch launch <pkg> <file> --container-mode isolated # Default
play_launch launch <pkg> <file> --container-mode observable
play_launch launch <pkg> <file> --container-mode stock
# Disable features
play_launch launch <pkg> <file> --disable-monitoring
play_launch launch <pkg> <file> --disable-diagnostics
play_launch launch <pkg> <file> --disable-web-ui
play_launch launch <pkg> <file> --disable-all
play_launch launch <pkg> <file> --disable-respawn
# Reload a composable node whose process crashed (default: off)
play_launch launch <pkg> <file> --composable-respawn on-crash # always
play_launch launch <pkg> <file> --composable-respawn inherit # only under a respawn="true" container
# Enable only specific features
play_launch launch <pkg> <file> --enable monitoring
play_launch launch <pkg> <file> --enable web-ui --enable diagnostics
# Adjust settings
play_launch launch <pkg> <file> --monitor-interval-ms 500
play_launch launch <pkg> <file> --web-addr 0.0.0.0:8080
play_launch launch <pkg> <file> --config config.yaml
# Logging
play_launch launch <pkg> <file> --verbose # Enable INFO level
RUST_LOG=play_launch=debug play_launch launch <pkg> <file> # DEBUG level
# Contracts
play_launch check <pkg> <file> [args...] # exit 0 / 1 errors / 3 refused
play_launch check <pkg> <file> --expect <rule-id> # pass only on exactly these errors
play_launch check <pkg> <file> --format json # diagnostics as JSON on stdout
play_launch check <pkg> <file> --explain --ascii --width 120
# Visualization
play_launch plot
play_launch plot --log-dir <dir>
play_launch plot --metrics cpu --metrics memory --metrics io --metrics gpu
play_launch plot --list-metrics
Development
Prerequisites
- ROS 2 (Humble on Ubuntu 22.04, Jazzy on 24.04)
- Rust toolchain (stable)
- Python 3.10+
- just command runner
- cargo-nextest test runner
- uv Python package manager
Install Dependencies
just install-deps
This installs colcon-cargo-ros2 and runs rosdep install for all ROS dependencies.
Build
just build # Full build: colcon + interception .so + wheel
just build-cpp # C++ only (msgs + container)
just build-rust # Rust only (assumes C++ install/ exists)
just build-wheel # Bundle + wheel only (no colcon rebuild)
Optional: grant the I/O helper its monitoring capability and the RT helper its
scheduling capability (requires sudo). After this, RT scheduling (--sched) works
without root:
play_launch setcap
Re-run it after every rebuild or upgrade. A file capability is bound to the exact contents of a binary, so replacing that binary drops it — deliberately, since carrying privilege across a change would grant it to code nobody vetted. play_launch says so when it happens, naming the grant it is replacing rather than telling you to run a command you already ran.
(A just setcap recipe also exists. It is a DEVELOPER convenience that avoids
the password prompt via a throwaway container, it needs a source checkout, and
it does not work under rootless Docker. play_launch setcap is the supported
path.)
Run
just run launch <package> <launch_file> [arguments...]
just run run <package> <executable> [arguments...]
Test
just test # Parser unit + fast integration (~3s)
just test-all # Parser unit + all integration (~30s)
just test-unit # Parser unit tests only
just test-integration # All integration tests
just test-autoware # Autoware integration tests
Code Quality
just check # clippy + rustfmt + ruff + cpplint + clang-format
just format # Auto-format Rust + Python + C++
just quality # Format then check
Install Wheel Locally
just install-wheel
License
MIT License. See LICENSE.txt.
Metadata
Release files for play-launch 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| play_launch-0.14.0-py3-none-manylinux_2_35_x86_64.whl | Python 3 | none | Linux glibc 2.35+ x86-64 | Details |
| play_launch-0.14.0-py3-none-manylinux_2_35_aarch64.whl | Python 3 | none | Linux glibc 2.35+ ARM64 | Details |
Total release size: 24.9 MB
Release files / play_launch-0.14.0-py3-none-manylinux_2_35_x86_64.whl
| Download URL | play_launch-0.14.0-py3-none-manylinux_2_35_x86_64.whl |
|---|---|
| Size | 13.0 MB |
| Tags | Linux glibc 2.35+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
28ae628182c0dc7d0e8a36c5143409891290beba5d05fdf81490dbcc963e696b
|
|
BLAKE2b-256 checksum How to use checksums |
f24349eb141214016db556e3055bc1adcde22250c8f496dabf26003c3d6aa412
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / play_launch-0.14.0-py3-none-manylinux_2_35_aarch64.whl
| Download URL | play_launch-0.14.0-py3-none-manylinux_2_35_aarch64.whl |
|---|---|
| Size | 11.9 MB |
| Tags | Linux glibc 2.35+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
6d71d5e5710f5605655937bef5fba16c1f1e51f82a91129f2d3105feb5adfdd2
|
|
BLAKE2b-256 checksum How to use checksums |
fe87eecbf39c23c74773ceb93ce5addf262475bb85d11bc2585f1bf3ec83717a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logSecurity for play-launch 0.14.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for play_launch-0.14.0-py3-none-manylinux_2_35_x86_64.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.