Launch files
Launch files let you start multiple nodes simultaneously, including those with dependencies on each other. With a single launch file, you or your team can recreate an entire node environment using just one command.
Running the example
Section titled “Running the example”Start by cloning this repository:
-
Clone the repository:
Terminal window git clone https://github.com/Peppy-bot/launchers-hub -
Navigate into the directory:
Terminal window cd launchers-hub
In the examples/ directory, you’ll find a launcher file for each language. Opening it reveals the following structure:
- The file is identified by
peppy_schema: "launcher/v1"at the root: peppy uses this to distinguish launcher files from nodepeppy.json5files (which use"node/v1") - All deployments are defined in the
deploymentsarray - Each deployment requires a
sourceandinstancesattribute. Besidesinstance_id, an instance can carryarguments,env_vars,links(one map filling every kind ofdepends_onslot, keyed bylink_id), anddefer_links(explicitly starting a required pairing or observer slot unresolved). Alinksvalue is interpreted against the slot it names: a producer slot (depends_on.{nodes,contracts}) takes a producer instance (a scalar for aoneslot, an array for a multi-cardinality slot); a pairing participant slot takes a single peer instance ("<peer>"or"<peer>/<peer_link_id>"to disambiguate); and an observer slot takes a single source instance to observe ("<source>"or"<source>/<source_link_id>")
The source attribute supports four formats:
- URL: A link to a
.tar.zstarchive, requiring bothurlandsha256attributes. The download is retried automatically on transient network failures (connection errors or5xxresponses); a mismatch againstsha256, or a client (4xx) error, fails immediately - Git repository: Requires
repo,path(location within the repo), andrefattributes - Local path: Specified via the
localkey, pointing to a directory on your filesystem. The path can be either absolute or relative to the launcher file - Repository: Reference a node that is already registered in your user repositories. Specify
nameandtag, or use the combinedname: "<name>:<tag>"shorthand. The node is resolved against your local nodes cache at~/.peppy/cache/nodes.json5.
// Repository source (long form){ source: { name: "openarm01_controller", tag: "v1", }, instances: [ { instance_id: "the_nervous_system" } ]}// Repository source (combined shorthand, equivalent to the example above){ source: { name: "openarm01_controller:v1", }, instances: [ { instance_id: "the_nervous_system" } ]}From within the cloned repository, execute the launcher:
peppy stack launch ./examples/python_robot.json5peppy stack launch ./examples/rust_robot.json5Peppy automatically inspects the name and tag of each node, verifies that all dependencies are met, and constructs the node stack in the correct order.
Launching from a repository
Section titled “Launching from a repository”Launchers discovered by peppy repo refresh (see Repositories) can be invoked by bare name, no path required:
peppy stack launch openarm01_sim_teleopAn argument that contains a path separator or ends in .json5 is always resolved as a filesystem path. A bare name (no separator, no extension) is first tried on disk as <name>.json5 next to your current directory, and only falls back to the repository cache at ~/.peppy/cache/launchers.json5 when no such file exists. Run peppy repo refresh first to ensure the launcher cache is populated. If the name resolves neither to a file nor to a cached launcher, the launch fails with an explicit “not found” error.
Verify that the node stack was configured correctly:
$ peppy stack list┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│ Core node: cn-adoring-wiles (host: robot-host) │├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤│ Node stack ││ ││ ┌──────────────────────────────────────┬───────┬───────────┬───────────────────────────────────────────────────────────┐ ││ │ NODE │ STAGE │ INSTANCES │ PATH │ ││ ├──────────────────────────────────────┼───────┼───────────┼───────────────────────────────────────────────────────────┤ ││ │ cn-adoring-wiles:v0.10.0 │ Root │ 1 running │ ~/workspace/peppy │ ││ │ fake_openarm01_controller:v1 │ Ready │ 1 running │ ~/.peppy/built_nodes/fake_openarm01_controller_v1.tar.zst │ ││ │ fake_robot_brain:v1 │ Ready │ 1 running │ ~/.peppy/built_nodes/fake_robot_brain_v1.tar.zst │ ││ │ fake_uvc_camera:v1 │ Ready │ 2 running │ ~/.peppy/built_nodes/fake_uvc_camera_v1.tar.zst │ ││ │ fake_video_reconstruction:v1 │ Ready │ 1 running │ ~/.peppy/built_nodes/fake_video_reconstruction_v1.tar.zst │ ││ └──────────────────────────────────────┴───────┴───────────┴───────────────────────────────────────────────────────────┘ ││ ││ Instance bindings ││ ││ ┌──────────────────────────────────────┬──────────────────────────────┬─────────┬─────────┬──────────────────────────────────────────────────────────────────────────────┐ ││ │ NODE │ INSTANCE │ STATUS │ HEALTH │ BINDINGS │ ││ ├──────────────────────────────────────┼──────────────────────────────┼─────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┤ ││ │ cn-adoring-wiles:v0.10.0 │ cn-adoring-wiles │ running │ healthy │ (none) │ ││ ├──────────────────────────────────────┼──────────────────────────────┼─────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┤ ││ │ fake_openarm01_controller:v1 │ vibrant-keller-2310 │ running │ healthy │ (none) │ ││ ├──────────────────────────────────────┼──────────────────────────────┼─────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┤ ││ │ fake_robot_brain:v1 │ zealous-bohr-5512 │ running │ healthy │ fake_openarm01_controller → vibrant-keller-2310@cn-adoring-wiles │ ││ │ │ │ │ │ fake_uvc_camera → mystic-galois-7701@cn-adoring-wiles │ ││ ├──────────────────────────────────────┼──────────────────────────────┼─────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┤ ││ │ fake_uvc_camera:v1 │ mystic-galois-7701 │ running │ healthy │ (none) │ ││ │ │ brave-noether-3098 │ running │ healthy │ (none) │ ││ ├──────────────────────────────────────┼──────────────────────────────┼─────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┤ ││ │ fake_video_reconstruction:v1 │ gallant-curie-4417 │ running │ healthy │ fake_uvc_camera → brave-noether-3098@cn-adoring-wiles │ ││ └──────────────────────────────────────┴──────────────────────────────┴─────────┴─────────┴──────────────────────────────────────────────────────────────────────────────┘ ││ ││ Dependencies ││ fake_robot_brain:v1 ➔ fake_openarm01_controller:v1 ││ fake_robot_brain:v1 ➔ fake_uvc_camera:v1 ││ fake_video_reconstruction:v1 ➔ fake_uvc_camera:v1 │└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘The output confirms that all nodes have been added to the stack along with their dependency relationships. The Instance bindings table breaks that down per instance: the consumers (fake_robot_brain, fake_video_reconstruction) list the depends_on slots they resolved, while the producers (fake_openarm01_controller, fake_uvc_camera) and the core node declare no slots and show (none). A resolved binding shows the chosen producer(s) as instance_id@core_node, ordered by link ID; a multi-cardinality slot lists every bound member in binding order, and a zero_or_more slot bound to nothing shows (empty set). Every declared slot except zero_or_more must be bound (a launcher that leaves one out is rejected at validation); see dependency cardinality.