SDK reference
Everything a card can declare and everything it receives at run time. A card is a folder with a manifest and an implementation; there is no plugin API to learn beyond what is on this page.
The manifest
card.json declares what the card is, what it accepts, and
every parameter that affects its output. It is also what draws the card in
the interface: there is no separate UI to write.
| Field | Type | Meaning |
|---|---|---|
id | string | Unique identifier, reverse-domain style |
name | string | Label shown on the canvas |
category | string | Palette section, dotted path |
inputs | array | Ports the card accepts |
outputs | array | Ports the card produces |
params | object | Every adjustable value |
run | object | Execution phase and entry point |
Port types
| Type | Carries |
|---|---|
Raw | Continuous recording, channels by samples |
Epochs | Segmented trials, trials by channels by samples |
Table | Tabular results, one row per unit of analysis |
Matrix | Square matrices, connectivity or distance |
Figure | A rendered plot |
Raw|Epochs | Accepts either; the card must handle both |
Parameter types
| Type | Extra keys | Renders as |
|---|---|---|
float | default, min, max, step, unit | Numeric field with unit |
int | same | Integer field |
bool | default | Toggle |
enum | values, default | Dropdown |
string | default, hint | Text field |
channels | multiple | Channel picker from the input |
params. A value hard-coded in the
implementation is treated as a bug, because it is invisible to the reader.The run context
The implementation exposes a single function, run(ctx). The
context carries the resolved inputs and parameters, and the helpers.
| Member | Description |
|---|---|
ctx.inputs["id"] | The object arriving on that port |
ctx.params["id"] | Resolved parameter value, after defaults and auto-resolution |
ctx.table(**cols) | Build a Table output from named columns |
ctx.matrix(array, labels) | Build a Matrix output |
ctx.log(msg) | Write to the run log, visible in the interface |
ctx.progress(fraction) | Report progress from 0 to 1 |
ctx.cache_key() | Stable key for the current inputs and parameters |
A complete card
{
"id": "user.spectral_entropy",
"name": "Spectral Entropy",
"category": "analysis.features",
"inputs": [{ "id": "in", "type": "Raw|Epochs" }],
"outputs": [{ "id": "out", "type": "Table" }],
"params": {
"fmin": { "type": "float", "default": 1.0, "unit": "Hz" },
"fmax": { "type": "float", "default": 40.0, "unit": "Hz" },
"n_per_seg": { "type": "int", "default": 512 },
"window": { "type": "enum", "values": ["hann", "hamming"] }
},
"run": { "phase": "analysis", "entry": "run.py" }
}import numpy as np from scipy.signal import welch def run(ctx): x = ctx.inputs["in"] f, pxx = welch( x.get_data(), fs=x.info["sfreq"], nperseg=ctx.params["n_per_seg"], window=ctx.params["window"], ) m = (f >= ctx.params["fmin"]) & (f <= ctx.params["fmax"]) p = pxx[..., m] / pxx[..., m].sum(axis=-1, keepdims=True) h = -(p * np.log(p + 1e-12)).sum(axis=-1) return { "out": ctx.table(entropy=h, unit="bits") }
Execution phases
The phase in run tells the engine where the
card belongs in the pipeline, which determines caching and ordering.
| Phase | Runs on |
|---|---|
io | Loading and writing files |
preprocessing.spatial | Re-referencing, channel operations |
preprocessing.temporal | Filtering, resampling |
epoching | Segmentation and trial rejection |
analysis | Features, statistics, decomposition |
visualisation | Figures |
Installing a card you wrote
Drop the folder into your user cards directory and it appears in the palette. No build step.
| Windows | %APPDATA%\Signal Studio\cards\user\ |
|---|---|
| macOS | ~/Library/Application Support/Signal Studio/cards/user/ |
| Linux | ~/.config/Signal Studio/cards/user/ |
To share it, zip the folder and publish it to the marketplace.
Errors
Raise a normal Python exception. The message reaches the interface and the run log, so make it say what a user can act on: which parameter, which channel, what was expected.