salpa-cli
The Salpa node authoring CLI. Scaffolds node packages that match the shipped template contract — the deterministic path to a new node — checks them against that contract, and puts them into the Salpa app on your machine.
python3 -m pip install salpa-cli
salpa new my-analyzer # interactive
salpa new my-suite -t multi-node-package --yes
salpa validate my_suite # will it install and register?
salpa push my_suite # into your running Salpa app
salpa unpush my_suite # and back out again
Installing adds the salpa command. If your shell can't find salpa afterward,
your Python scripts directory isn't on your PATH —
installing into a virtual environment is the simplest fix (it puts salpa on PATH).
salpa new creates ./<under_scored_name>/ from a bundled template, with every
placeholder substituted and the directory underscored (the dir name becomes the
Python package name, so a hyphen would break from .core import ...; meta.toml's
name stays kebab-case).
Templates
Templates ship inside the wheel and are the single source of truth for the node contract, so there is no second copy to drift.
| Template | For |
|---|---|
individual-node |
one node with its own pixi env (default) |
multi-node-package |
several related nodes sharing one pixi env, chained via predecessor_data |
Options
salpa new [NAME]
-t, --template individual-node | multi-node-package
-d, --description one-line description
--author author name
--category UI category (e.g. "Cheminformatics")
-o, --output directory to create the package in (default: .)
-y, --yes non-interactive: accept defaults, no prompts
--install run `pixi install` in the new package afterwards
Validating
salpa validate [PATH] checks a package against the contract the app enforces at
install and registration time. Every check maps to a real failure — a node missing
from [package.nodes], a shared-environment name that drifted between three files,
a stray per-node pixi.toml that silently opts a node out of the shared env. It is
not a linter: style is not checked.
salpa validate [PATH] # default: the current directory
--strict # warnings become errors (CI)
--ignore CODE # suppress one check by code, repeatable
--json # machine-readable report
--no-import # skip the import checks
--python PATH # override the auto-detected import-check interpreter
Exit codes: 0 clean · 1 at least one error · 2 the path is not a package.
Findings are ERROR (will not install or will not register) or WARN (installs,
but is probably not what you meant). Each carries a stable code (E3, S2, …) so
it can be quoted, grepped, and suppressed.
Import checks. I1-I3 import your node.py in a subprocess to confirm the
app can read its OPTIONS. They need the authoring SDK (bocoflow_core), and the
interpreter that has it is found for you — your package already declares the SDK in
its own pixi.toml, so its solved test environment is the right one to judge the
package against:
pixi install -e test # solve the test env — the one your pixi.toml puts the SDK in
salpa validate # the import checks now run, no flags
The search order, first hit wins: .pixi/envs/test → .pixi/envs/default → the
interpreter running salpa. A candidate that cannot import bocoflow_core is
passed over, and the report names the one that answered. pip install bocoflow-core-sdk beside salpa works too, and --python PATH overrides the
search entirely (a --python that lacks the SDK skips rather than falling back —
naming an interpreter is an instruction, not a hint).
With no interpreter at all, the checks are skipped, and both the status line and
the summary say so — No findings (import checks skipped) is a smaller claim than
No findings. This package should install and register., and reads as one.
Suppressing a check. Some warnings describe a shape that is occasionally
correct — E3 (a per-node pixi.toml) is a deliberate opt-out when a node's
dependencies conflict with its package's shared environment. --ignore lets such a
package pass --strict without silencing everything:
salpa validate --strict --ignore E3
Suppressed findings are still reported (and appear under suppressed in --json)
— they are hidden from the exit code, not from you.
salpa new runs a validation pass over its own output and prints a one-line
summary. That pass covers structure, naming and environment only; the import
checks are left to salpa validate.
Pushing it into Salpa
salpa push [PATH] makes a package appear in your running Salpa app's
Marketplace ▸ Browse, ready to install.
It is not publishing. It targets the app on your machine; nothing is uploaded anywhere, and there is no public hub involved.
salpa push [PATH]
--copy copy into the app instead of linking your directory
--source-id id for this source in the app
--source-name display name for this source
--port port the app is listening on (default 18000, or $SALPA_PORT)
--force push despite `salpa validate` errors; with --copy, also
replace a package copy that this push did not create
-y, --yes accept the layout change without asking
Exit codes: 0 ok · 1 refused or failed · 2 the path is not a package.
push validates, arranges your package into the layout a package source uses
(registry.json + packages/<pkg>/, asking before it moves anything), generates
the catalog file, and asks the app to sync it and put the package on the shelf.
The install itself stays in the app. push stops at the shelf — installing is
user-consented in the UI, and runs the same installer every other package goes
through. There is no second installer in this CLI, and no assumption anywhere about
where the app keeps its files: the app is asked, over the API its own UI uses.
Salpa must therefore be running; if it isn't, push says so and stops.
By default your directory is the source — nothing is copied, so re-running after an edit refreshes what the app offers:
salpa push packages/my_suite # edit, push, repeat
--copy copies the package into the app instead. Self-contained and survives
moving your working copy, at the cost of needing another --copy push per edit.
It lands in the directory the app keeps its own packages in, so it will replace an
earlier copy of yours but refuses to overwrite anything else — your [package].name
decides the directory name, and a collision there is someone else's package.
Taking it back out
salpa unpush [PATH] is the reverse: it removes the package from the app's shelf
and deregisters the source, so the app stops offering it.
salpa unpush [PATH]
--source-id id of the source to remove (default: whichever the push created)
--port port the app is listening on (default 18000, or $SALPA_PORT)
--force remove it even though the package is installed
-y, --yes remove without asking
Exit codes: 0 ok (including nothing to remove) · 1 refused or failed · 2 the
path is not a package.
Your own directory is never touched — the packages/ layout and registry.json
that push wrote stay put, and salpa push registers them again whenever you want
the package back. You do not have to remember whether you used --copy: unpush
reads which mode was used off what is actually in the app, and cleans up the copy
in the app's catalog when there is one.
Unpushing something that was never pushed reports Nothing to remove and exits 0,
so it is safe to run twice.
unpush refuses while the package is installed, and points you at
Marketplace ▸ Installed to uninstall it first — removing the source out from under
an installed copy would leave it pointing at a source that no longer exists.
--force removes it anyway. As with push stopping at the shelf, unpush never
uninstalls anything itself; that stays in the app.
Full walkthrough: salpa docs publishing-to-your-app.
Authoring guide
salpa docs prints the bundled node-authoring guide. Full documentation:
https://salpa.app/docs/custom-nodes
Reserved
salpa publish / install / run are reserved for later and not implemented
yet. The current surface is salpa new, salpa validate, salpa push,
salpa unpush and salpa docs.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file salpa_cli-0.3.1-py3-none-any.whl.
File metadata
- Download URL: salpa_cli-0.3.1-py3-none-any.whl
- Upload date:
- Size: 95.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c7b07a2dc4b52ab642dee0b8f535f8539ddc8924417b7e48aebe5a4a9bce696
|
|
| MD5 |
4b89d1687c8aed799574a1ac4502ad67
|
|
| BLAKE2b-256 |
44223df8efc8840864b88f7fc16c8ee4b6cd80fdb08d1c90b7c35a8ec992090c
|