Skip to content

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.

Start by cloning this repository:

  1. Clone the repository:

    Terminal window
    git clone https://github.com/Peppy-bot/launchers-hub
  2. 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:

  1. The file is identified by peppy_schema: "launcher/v1" at the root: peppy uses this to distinguish launcher files from node peppy.json5 files (which use "node/v1")
  2. All deployments are defined in the deployments array
  3. Each deployment requires a source and instances attribute. Besides instance_id, an instance can carry arguments, env_vars, links (one map filling every kind of depends_on slot, keyed by link_id), and defer_links (explicitly starting a required pairing or observer slot unresolved). A links value is interpreted against the slot it names: a producer slot (depends_on.{nodes,contracts}) takes a producer instance (a scalar for a one slot, 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.zst archive, requiring both url and sha256 attributes. The download is retried automatically on transient network failures (connection errors or 5xx responses); a mismatch against sha256, or a client (4xx) error, fails immediately
  • Git repository: Requires repo, path (location within the repo), and ref attributes
  • Local path: Specified via the local key, 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 name and tag, or use the combined name: "<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:

Terminal window
peppy stack launch ./examples/python_robot.json5

Peppy automatically inspects the name and tag of each node, verifies that all dependencies are met, and constructs the node stack in the correct order.

Launchers discovered by peppy repo refresh (see Repositories) can be invoked by bare name, no path required:

Terminal window
peppy stack launch openarm01_sim_teleop

An 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.