Skip to content

Concepts

A Node is the fundamental unit of computation in PeppyOS. It represents a runnable application or service that can expose interfaces (topics, services, actions) and consume interfaces from other nodes.

A node is defined by its configuration file (peppy.json5) which includes:

  • Manifest: The node’s identity
  • Build: Commands to build and launch the node
  • Parameters: Configuration values passed to the node
  • Interfaces: What the node exposes and consumes

The manifest defines a node’s identity:

FieldDescription
nameA validated identifier (ASCII letters, digits, _, -)
tagA version or variant identifier (e.g., donut, v1.0.0)
labelsOptional metadata labels
variantsOptional list of alternative node implementations
depends_onOptional dependency declarations on other nodes

A node is uniquely identified by its name:tag combination.

The execution section defines how to prepare and launch the node:

FieldDescription
languageThe programming language of the node (rust, python)
parametersOptional parameter schema for runtime configuration
build_cmdCommand to run during the node build phase
run_cmdCommand to launch the node
containerOptional container configuration (mutually exclusive with build_cmd/run_cmd)

Nodes communicate through three types of interfaces:

TypeDescription
TopicPublish/subscribe messaging for streaming data
ServiceRequest/response communication for synchronous calls
ActionLong-running tasks with feedback and cancellation support

A node can expose interfaces (make them available to others) and consume interfaces from other nodes.

A Node Instance represents a single running execution of a node. Each instance has:

  • Instance ID: A unique identifier for this running process
  • PID: The process ID (when running locally)

A node can have multiple instances running simultaneously. For example, you might run multiple instances of a camera node, each connected to separate physical devices.

The Node Stack is the central data structure that manages all active nodes in the system. It maintains a directed acyclic graph (DAG) where:

  • Vertices are node entities
  • Edges represent dependency relationships, pointing from a dependent node to its dependency. These edges are derived from interface connections between nodes (exposers and consumers).
  1. Dependency Management: Tracks which nodes depend on which other nodes
  2. Interface Validation: Ensures nodes expose the interfaces their dependents require
  3. Instance Lifecycle: Manages the creation and removal of node instances
  4. Root Node: Always contains a root node (the core node) that cannot be removed
  1. Validates that all required dependencies exist
  2. Checks that dependencies expose the required interfaces
  3. Tracks pending requirements when dependencies are not yet available
  4. Resolves pending requirements when dependencies are added

The node stack can be visualized in multiple formats:

  • DOT format: For Graphviz visualization of the dependency graph
  • Serialized graph: JSON representation for programmatic access

The Core Node is a special node that serves as the root of the node stack and is always present. It is responsible for:

  • Dependency Creation: When a node consumes an interface, the core node creates a dependency on the node that exposes that interface
  • Stack Management: Managing the lifecycle of all other nodes in the system
  • System Coordination: Acting as the central coordinator for the local PeppyOS runtime

Each PeppyOS runtime has exactly one core node that manages its local DAG of nodes. In a distributed deployment, multiple runtimes — each with their own core node — can run on separate machines. The core nodes operate independently, managing their local node stacks without a centralized controller. Nodes communicate across runtimes through the shared messaging layer, enabling a fully decentralized system where each core node is responsible only for its own set of nodes.

Node Stack
├── Core Node (always present)
│ └── Instance (always a single instance)
└── Other Nodes
├── Node A
│ ├── Configuration
│ └── Instances (1 or more)
└── Node B
├── Configuration
└── Instances (1 or more)