🚧Documentation is under active development β€” content may be incomplete or change frequently.
Skip to Content
Build Custom Nodes

Build Custom Nodes

Extend Salpa with your own computational nodes. If you can write a Python function, you can build a Salpa node.

Overview

Building a custom node involves three steps:

  1. Write your science code in core.py β€” pure Python, no Salpa dependencies
  2. Create a node wrapper in node.py β€” define inputs, outputs, and UI configuration
  3. Add metadata in meta.toml β€” name, version, category, and hashtags for discovery

Quick start: Hello World

The simplest possible node. Start here to understand the pattern.

1. Create the directory

my_hello_world/ β”œβ”€β”€ meta.toml β”œβ”€β”€ node.py β”œβ”€β”€ core.py └── README.md

2. Write core.py

Your science code, with no framework dependencies:

def run_hello(name: str = "World") -> str: """Generate a greeting message.""" message = f"Hello, {name}! This is my first Salpa node." return message

3. Write node.py

The Salpa wrapper that defines UI and execution:

from bocoflow_core.node import IONode OPTIONS = { "name": { "label": "Your Name", "type": "text", "default": "World", "description": "Name to include in the greeting" } } class MyHelloWorld(IONode): def execute(self, predecessor_data, flow_vars): from .core import run_hello name = self.options.get("name", "World") result = run_hello(name) self.set_output("message", result) return {"message": result}

4. Write meta.toml

[package] name = "my-hello-world" version = "0.1.0" description = "A simple greeting node" category = "utility" author = "Your Name" [package.hashtags] tags = ["hello-world", "tutorial", "getting-started", "utility"]

5. Install and test

Copy your node directory to the nodes installation path and restart the server. Your node will appear in the Node Library.

Adding Python dependencies

If your node needs external libraries (NumPy, BioPython, MDAnalysis, etc.), add a pixi.toml:

[project] name = "my-analysis-node" channels = ["conda-forge"] platforms = ["osx-arm64", "osx-64", "linux-64", "win-64"] [dependencies] python = ">=3.11" numpy = ">=1.26" biopython = ">=1.83"

When pixi.toml is present, Salpa automatically:

  • Creates an isolated Python environment for the node
  • Installs all specified dependencies
  • Runs the node in a subprocess (no conflicts with other nodes)

Node configuration options

The OPTIONS dictionary defines the configuration UI. Supported field types:

TypeDescriptionExample
textSingle-line text inputSequence name, output prefix
textareaMulti-line text inputFASTA sequence, notes
numberNumeric inputTemperature, step count
selectDropdown menuForce field selection
fileFile pickerInput PDB, topology file
checkboxBoolean toggleEnable/disable options

File input example

OPTIONS = { "input_file": { "label": "Input Structure (.pdb)", "type": "file", "extensions": [".pdb", ".gro"], "description": "Molecular structure file" }, "force_field": { "label": "Force Field", "type": "select", "options": ["amber99sb", "charmm27", "oplsaa"], "default": "amber99sb" } }

Logging and progress

Use stream_log() to show real-time progress in the UI:

from bocoflow_core.stream_logger import stream_log def execute(self, predecessor_data, flow_vars): stream_log("Starting computation...", node_id=self.node_id, progress=0) # ... do work ... stream_log("Processing step 1/3...", node_id=self.node_id, progress=33) # ... more work ... stream_log("Processing step 2/3...", node_id=self.node_id, progress=66) # ... finish ... stream_log("Complete!", node_id=self.node_id, progress=100)

Progress updates stream in real-time to the execution panel via WebSocket.

Best practices

  • Keep core.py framework-free β€” It should work as a standalone Python script
  • Use pixi.toml for external dependencies β€” Never assume system packages are available
  • Add demo_data/ β€” Include example input files so users can test immediately
  • Write descriptive hashtags β€” 5-10 hashtags in meta.toml help users find your node
  • Log progress β€” Use stream_log() at key execution stages (0%, 25%, 50%, 75%, 100%)
  • Handle errors gracefully β€” Catch exceptions in execute() and provide helpful error messages

Next steps

  • Node System β€” Understand the full node architecture
  • Features β€” Explore all Salpa capabilities