Node System
A node is one computational step. A workflow is nodes wired together on a canvas, executed in dependency order. That’s the whole model.
Salpa ships with the Hello World Pipeline as a worked example you already have installed — three nodes that encrypt a message, decrypt it, and write a side-by-side comparison report. Pure Python, no dependencies, runs in seconds. The rest of this page is a tour of that pipeline.
Run it
- Open Salpa. Click New Workflow, give it a name, and pick a working directory.
- In the Node Library or the Templates dialog, find Hello World Pipeline and load it.
- The canvas now shows three connected nodes:
Hello Encrypt→Hello Decrypt→Hello Reveal. - Click Execute All.
You’ll see status indicators light up in order. When the run finishes, three files appear in your working directory:
demo_encrypted.txt Ciphertext from Encrypt
demo_decrypted.txt Recovered plaintext from Decrypt
demo_reveal.txt Side-by-side comparison report from RevealOpen demo_reveal.txt. That report — character mapping, statistics, the whole thing — was built by a node that read two files written by the two upstream nodes. You just ran a real data pipeline.
Anatomy of a node on the canvas
Each node on the canvas is a box with five things you can interact with:
| Element | What it is |
|---|---|
| Body | The node itself. Click it to open the configuration panel on the right. |
| Input ports | Dots on the left. Wires coming in deliver data from upstream nodes. |
| Output ports | Dots on the right. Wires going out feed downstream nodes. |
| Status indicator | Color-coded dot showing idle, queued, running, completed, or failed. |
| Side panel | Form on the right where you set the node’s parameters. |
When you connect two nodes, you’re saying “the output of A flows into B.” Salpa figures out the execution order from the graph.
What flows on the wires?
A wire doesn’t carry “the whole world.” It carries a small dictionary that the upstream node returns. In the Hello World Pipeline, the only thing that flows between nodes is case_name — the identifier used to name output files.
Here’s the real fallback logic from Hello Encrypt (full source):
# hello_encrypt/node.py
case_name = flow_vars["case_name"].get_value()
if not case_name and predecessor_data:
input_data = predecessor_data[0] if predecessor_data else None
if input_data and isinstance(input_data, dict):
case_name = input_data.get("case_name", "secret")
if not case_name:
case_name = "secret"The pattern: each node reads its own configured value first, then falls back to whatever the upstream node sent, then falls back to a hardcoded default. Other parameters — the message text, the cipher shift, the output directory — are configured independently on each node. That’s what makes nodes composable: each one can stand alone, with predecessor data as a hint rather than a hard dependency.
Anatomy of a node on disk
A node package is just a directory. The minimum viable node has two files:
hello_encrypt/
├── meta.toml The manifest — name, class, hashtags
├── node.py The code — parameters and execute()
├── README.md Optional: documentation shown in the marketplace
└── pixi.toml Optional: triggers isolated environmentLarger packages add core.py (pure logic), tests/, and demo_data/, but the manifest plus a Python file is the whole irreducible core.
View the source. The full Hello World Pipeline source is published alongside this site. Open any file in your browser, or right-click and save it to disk:
File Purpose package.tomlMulti-node bundle manifest workflows/hello-world-pipeline.jsonThe pre-wired workflow template hello_encrypt/meta.toml·node.py·README.mdThe Encrypt node hello_decrypt/meta.toml·node.py·README.mdThe Decrypt node hello_reveal/meta.toml·node.py·README.mdThe Reveal node
Here’s the real manifest for Hello Encrypt (view full file):
# hello_encrypt/meta.toml
[package]
name = "hello-encrypt"
version = "1.0.0"
description = "Encrypts a message using a Caesar cipher and writes the ciphertext to a file"
author = "BoCoFlow Development Team"
license = "MIT"
[node]
class_name = "HelloEncrypt"
display_name = "Hello Encrypt"
hashtags = [
"hello-world",
"encryption",
"starter",
"tutorial",
"text-output",
"beginner",
]
[node.metadata]
tooltip = "Encrypts a message with a Caesar cipher and writes the ciphertext to a file"class_name ties to the Python class in node.py. display_name is what you see on the canvas. hashtags drive search and grouping in the Node Library — there’s no rigid category hierarchy. Five to ten descriptive hashtags is the sweet spot.
For the Python side, see Build Custom Nodes — that page dissects this same node line by line.
Execution strategies
Salpa picks an execution strategy automatically based on what’s in the package directory:
| Strategy | When | What happens |
|---|---|---|
| In-process | No pixi.toml | Runs directly in the worker process. Fast startup, no isolation. |
| Pixi subprocess | pixi.toml present | Creates an isolated Python environment, runs the node in a subprocess. Full dependency isolation. |
| Container | Reserved | Docker/Podman execution. Implemented but not currently used. |
| HPC / SLURM | Vendor-specific | Remote cluster execution via SSH. Configured per node, not auto-detected. |
The Hello World Pipeline runs in-process because none of its three nodes have a pixi.toml — that’s why it starts instantly. Heavier nodes like pdb2pqr or esmfold-prediction ship a pixi.toml, and Salpa creates an isolated Python environment for them on first run. Your existing nodes don’t see those dependencies. Their nodes don’t see yours.
A handful of nodes — including the Hello World Pipeline — ship pre-installed with Salpa. If you ever uninstall one, you can reinstall it from the marketplace offline; no network connection required.
Naming conventions
Salpa uses different cases in different contexts:
| Context | Convention | Example |
|---|---|---|
| Display name (canvas, palette) | Title Case | Hello Encrypt |
Package name (meta.toml) | kebab-case | hello-encrypt |
| Directory name | snake_case | hello_encrypt/ |
| Python class | PascalCase | HelloEncrypt |
The reason: Python imports require snake_case directories, but kebab-case is the standard for distributable package names, and Title Case reads better in the UI.
What’s next
- Build Custom Nodes — dissect
Hello Encryptline by line and write your own - Getting Started — install Salpa and run your first workflow