DocsBCINexus Edge
BCILattice Documentation

BCINexus Edge

Run the models you trained in BCILattice on a Raspberry Pi, a Jetson or any Linux board: signed BCINexus model files, a loop rate and signal source you set in the app, your own code, simulation on your computer, and devices verified with BCINexus while they run.

v1.0BCINexus Platform · 2026-09-15[email protected]

What BCINexus Edge does

A trained model inside BCILattice needs BCILattice to run. BCINexus Edge takes it out: it turns the model into a BCINexus model file, lets you decide how it runs — how often, on which signal, with which code — and installs that on your edge hardware as a service that starts with the board.

BCILattice (your computer)                BCINexus                    Edge device
  trained model  ──export──▶  .bnxm  ──sign──▶  certificate  ──deploy──▶  bcinexus-edge service
  loop, source, code  ─────▶  .bnxd  ──sign──▶  certificate               reads the signal
  simulate here (no device)                                              runs the models at the rate
                                                  lease  ◀──────────────  asks to run (every few min)

Everything that decides what the device does is signed by BCINexus, so the device runs it exactly as you made it, and nothing else. To change anything — the rate, a model, a path, a line of code — you change it in BCILattice and deploy again.

The files

FileWhat it is
.bnxm — BCINexus modelOne trained model. The only model format you handle, whatever library trained it; the engine that runs it on the device is chosen for you. Encrypted for the devices it was exported for (and your computer, for simulation), and signed by BCINexus.
.bnxd — deploymentWhich models run and where each file lives on the device, the loop rate, the signal source, conditioning filters, outputs, your custom code (by its hash), how long a dropped connection is tolerated, and the devices it is for. Signed by BCINexus.
app.pyOptional custom code. The deployment pins its exact bytes; an edited copy does not run.

A model file is not an ONNX, PyTorch or scikit-learn file, and no other tool can open it. That is deliberate: it is what lets the device refuse a model that was changed, copied to a board it was not issued for, or used by another account.

Setting up a device

What a board needs

  • Linux with systemd (Raspberry Pi OS, Ubuntu, Debian, Jetson Linux).
  • Python 3.9 or newer, with python3-venv.
  • SSH access from your computer, and administrator (sudo) rights on the board.
  • An internet connection while it runs. The device is checked with BCINexus every few minutes; setup and deployment also need internet to install packages and register.

Microcontrollers (Arduino, ESP32) cannot run BCINexus Edge; they have no Linux or Python.

What setup does

In BCINexus Edge → Overview & Connect, connect over SSH, then in Devices choose Set up the connected board. BCILattice:

  1. Checks the board (architecture, Python, systemd).
  2. Installs the BCINexus Edge runtime into its own environment under /opt/bcinexus, owned by root, and creates a system user bcinexus with no login to run it.
  3. Has the board generate its own keys. Private keys never leave the board; only the public halves are read back.
  4. Registers those public keys with BCINexus under your workspace. This uses one of your edge devices.
  5. Stores the device certificate BCINexus returns on the board.

If sudo on the board asks for a password, enter the device password in the connection settings; it is sent to sudo on its input, never written into a command line.

Exporting models

Everything below happens in BCINexus Edge → Model Export, and does not need a device until you deploy.

Which models can be exported

Trained in the ML Suite asExportable when
A deep-learning model (PyTorch)The run was trained with a BCILattice build that includes BCINexus Edge. At the end of training the model is captured in a self-contained form and checked against the live model. Runs trained earlier are listed with “Re-run this training to export it”.
A machine-learning estimator (scikit-learn)The run kept its scored rows, and the estimator is the node that produced the run’s predictions. A preprocessing step on its own is refused.

Models that cannot be exported are shown greyed out; hover one to see why.

The export is checked against the trained model

Before a model file is offered for signing, BCILattice opens it with the same runtime the device uses and runs it on the rows the model was checked with during training. Every prediction must match, and class probabilities must agree to within 0.0001. If they do not, the export stops and says by how much.

What the check covers

The model itself. It does not cover what happens to the signal before the model — the conditioning filters you set, or features your custom code computes. Those must match how the model was trained; see Limitations.

Several models, names and paths

Tick as many models as the deployment should run (up to 16). Each gets a name in code (letters, digits and underscores, e.g. motor_imagery) and a path on the device. The path defaults to /opt/bcinexus/models/<name>.bnxm; change it to any absolute path ending in .bnxm. The path is part of the signed deployment.

Signal

Sources

SourceUse it for
Lab Streaming LayerYour amplifier, by stream type or name. Find streams lists what is on the network and fills in the sampling rate.
Synthetic test signalTesting a deployment end to end without hardware.
Recording (replay)A .npy or .csv file of samples × channels, played back in real time. Mainly for simulation.
BCINexus hardwareReserved for BCINexus acquisition hardware. Its driver is not released; a device configured this way reports that plainly.

The sampling rate must be the rate the model was trained at; a stream at a different rate is refused rather than silently resampled. Channels are optional names (C3, Cz, C4): when given, the device picks the model’s channels out of the stream by name; when not, the channel count must match.

Conditioning filters

A band-pass and a 50 or 60 Hz notch can be applied on the device as the signal arrives. They are causal (they never look ahead) and keep their state from one chunk of signal to the next, so each sample is filtered exactly once.

Loop rate

Choose how often the models run: per second or per minute, from once an hour to 1000 times a second. Every model in the deployment runs on each tick.

Measure on this computer and Measure on the device time every model end to end and recommend a maximum rate: the sum of each model’s 95th-percentile time, with 50 % headroom. Sized to the median, a loop would miss its deadline on every second tick.

If a tick runs late by more than a whole period, the missed ticks are counted and skipped; the device never fires a burst of stale predictions to catch up. The count appears in the device’s status.

Where results go

OutputWhat arrives
System journal (always)One JSON line per result, kept by the board’s logging.
A file on the deviceJSON lines, rotated by size. Must be under /var/lib/bcinexus, the only place the service may write.
UDPOne JSON datagram per result, for a local controller, robot or game engine.
LSL streamA string stream other LSL tools can record or react to.

A prediction record carries the model name, the value (the class it was trained with), confidence, class scores, latency and the tick number.

Custom code

By default every tick runs every model and emits its prediction. Tick Run my codeto decide what happens instead — combine models, act only on confident answers, compute your own features. Insert template writes a starting point for the models you ticked:

  • Predict with every model
  • Combine models — average their class scores
  • Command on confident, stable predictions — a confidence floor and a debounce
  • Compute features from the live window — for models trained on features
def on_start(ctx):                  # optional
    ctx.state["sent"] = None

def on_tick(ctx):                   # required; runs at the deployment's rate
    p = ctx.predict("motor_imagery")  # newest window, that model's channels
    if p is None:                   # still collecting the first window
        return None
    if p.confidence >= 0.7 and p.value != ctx.state["sent"]:
        ctx.state["sent"] = p.value
        return {"command": p.value}  # a returned dict is emitted as a result

def on_stop(ctx):                   # optional
    ctx.log("stopped")
ctxWhat it gives you
predict(alias)Window + prediction for one model; None while warming up
window(alias=None, samples=None)The newest [channels, samples] of signal
modelsEvery model, by name (predict, predict_batch, classes, …)
emit(dict), log(msg)Send an event or a log line to the outputs
sampling_rate, channels, rate_hz, tick, nowWhere the loop is
stateA dictionary that persists between ticks

The code is part of the signed deployment by its SHA-256. It is written and changed in BCILattice; an edited copy on the device fails verification and does not run. After 50 consecutive errors from on_tick the service stops and reports the last one.

Simulating on your computer

Build & simulate here exports the models, checks them, and runs the whole deployment — source, filters, rate, your code — on your computer with the device runtime itself. Predictions stream into the log until you press Stop.

Simulation needs no device, no signing and no lease, and does not use an edge device from your allowance. The simulation key only works on the computer that created it, so it cannot be used to run models on a board.

Signing and deploying

  1. Tick the registered devices the deployment is for, and set how long a dropped connection is tolerated.
  2. Sign for ticked devices sends BCINexus each model file’s manifest(its description and hashes) and the deployment settings. Model weights and training data are never sent.
  3. Sign & deploy to connected board also installs everything on the board you are connected to, restarts the service, verifies every file on the board, and fetches its first lease.

A signed bundle is kept on your computer, so you can deploy the same deployment to each of its devices in turn.

Using a model from your own code

The runtime installed on the board is also a Python library you can use in your own programs on it:

from bcinexus import model_loader

model = model_loader()                    # automatic: the deployment on this board
                                          #   (a ModelSet when it has several models)
mi = model_loader(alias="motor_imagery")  # one model of that deployment

prediction = mi.predict(window)           # window: [channels, samples]
print(prediction.value, prediction.confidence, prediction.latency_ms)

Loading a model file from any path

Yes — pass the path of a .bnxm file, wherever it is on the board:

from bcinexus import model_loader

model = model_loader("/home/pi/models/motor_imagery.bnxm")

The file still has to be one BCINexus will run there:

  • it was exported for this device (a file exported for another board does not open, even if you copy it across);
  • it is unchanged since export;
  • the board is registered to your workspace, within your allowance, and connected to the internet so BCINexus can verify it.

Moving or renaming the file does not matter to your own code. It does matter to the service, which loads files from the paths signed into the deployment: if you move a file it uses, change the path in Model Export and deploy again.

Internet connection and device checks

Internet is required

BCINexus Edge is not an offline product. A device must be connected to the internet so that BCINexus can verify it is registered to your workspace, within your edge-device allowance, and still allowed to run these models.

While it runs, the device checks in with BCINexus every few minutes. It proves it is itself with its own key; it never holds your account’s password or session. Each successful check is a lease: permission to keep running until the next one.

SituationWhat the device does
Connected, all in orderRuns.
Connection drops brieflyKeeps running for a short tolerance you set in the deployment (30 minutes by default; BCINexus allows 5 minutes to 72 hours), so a Wi-Fi hiccup does not stop a session.
Still disconnected after thatPauses and says so; resumes by itself as soon as it can reach BCINexus again.
BCINexus refuses the deviceStops at once and stays stopped: the device was removed, its access was revoked, the workspace no longer has BCINexus Edge, or the device is beyond the allowance.
Not yet connected since deploymentDoes not start predicting until BCINexus has verified it once.

The tolerance is counted on the board’s monotonic clock and saved every few seconds in a tamper-evident file, so changing the clock does not extend it and restarting the board does not reset it.

Edge devices and your allowance

  • An edge device is a board you deploy to. It is a separate count from BCILattice seats and from the computers you sign in on; one never uses up another.
  • Individual accounts buy edge devices one at a time; a Lab gets a shared set used by everyone in the lab. Prices are on the pricing page.
  • You can remove a device to free its slot once every 7 days. A removed device stops at its next check with BCINexus.
  • If you have more registered devices than your allowance (for example after reducing the number you pay for), the devices registered earliest keep running and the newest stop.
  • Simulation on your computer never uses an edge device.

What is protected, and how

If someone……then
edits a model file, the deployment or the codethe signature or hash check fails and it does not run
changes the loop rate or a path on the boardthe deployment no longer matches its certificate
copies a model file to another boardit cannot be decrypted there, and was not certified for that board
swaps a model for a different signed onethe deployment names each model by hash, so the swap is detected
signs their own filethe device only trusts BCINexus’s keys; there is no setting to add one
disconnects the board to avoid the checkit pauses once the short tolerance for a dropped connection runs out
edits the saved tolerance counterthe file reads as damaged and the device must be verified again

On the board, the service runs as a dedicated user that cannot change its own models, deployment or code, and systemd confines it to writing its own state directory.

On the device: bcinexus-edge

Every command prints JSON. None of them can change the rate, the models, the source or the code.

CommandDoes
bcinexus-edge verifyChecks every installed file without running anything
bcinexus-edge statusThe running service’s state, ticks, late ticks, latency and lease
bcinexus-edge leaseAsks BCINexus for a lease now
bcinexus-edge benchmarkTimes the deployed models on this hardware
bcinexus-edge identity showThe device’s public keys and registration
bcinexus-edge versionRuntime and file-format versions

The service is bcinexus-edge under systemd: systemctl status bcinexus-edge, journalctl -u bcinexus-edge. BCILattice’s Service status on the board shows both.

When something is wrong

MessageMeaning and fix
“Re-run this training to export it”A deep-learning run from before BCINexus Edge. Train it again.
“does not reproduce the trained model”The export check failed; nothing was exported. Report it with the run.
“needs a password” during setupEnter the board’s password in the connection settings.
“Install venv support”On the board: sudo apt install python3-venv.
“has not been authorised by BCINexus yet”The board has not reached BCINexus since deployment. Connect it to the internet.
“offline longer than its offline allowance”The connection has been down longer than the tolerance. Reconnect it; it resumes by itself.
“BCINexus refused this device”Removed, revoked, over the allowance, or Edge no longer active. Check Devices in BCILattice.
“was trained on N Hz data but the signal arrives at M Hz”Set the stream (or the sampling rate) to match the model.
“changed after it was deployed”A file on the board was edited. Deploy again from BCILattice.
“not one of the devices this deployment was signed for”Tick the connected board under Devices and sign again.

Limitations

What BCINexus Edge does not do today, stated plainly.

Hardware and platforms

  • Linux boards only (systemd, Python 3.9+). No Arduino, ESP32 or other microcontrollers, and no Windows or macOS devices — those computers can simulate, not host a deployment.
  • CPU inference only. A Jetson’s GPU is not used yet.
  • Large installs for deep-learning models. PyTorch on a small board is hundreds of megabytes and the first install can take many minutes; it needs internet.
  • No over-the-air updates. The runtime and deployments update only when you deploy from BCILattice.
  • BCINexus acquisition hardware is not supported until its driver is released.

Models

  • Deep-learning models trained before BCINexus Edge cannot be exported; train them again.
  • A model whose computation changes with its input (data-dependent branching, non-tensor inputs or outputs) cannot be captured, and says so.
  • A scikit-learn model must be one estimator. A chain of separate nodes (a scaler node, then a classifier node) cannot be exported as one model.
  • Analysis Suite preprocessing is not part of the model file — filtering, ICA, epoching, feature extraction. Reproduce it on the device with conditioning filters or custom code.
  • The export check confirms the model matches training. It cannot confirm that your filters or features match what the model was trained on.
  • No quantisation or model compression step; the model runs as trained.

Signal and timing

  • The stream’s sampling rate must equal the model’s; there is no resampling. LSL streams with an irregular rate are not supported.
  • The loop runs from once an hour to 1000 times a second; what a board actually sustains depends on its hardware. Late ticks are skipped, not caught up.
  • Linux is not a real-time operating system; tick timing can jitter under load.

Internet and licensing

  • Internet is required. A device must be connected so BCINexus can verify it. It is not an offline product: without a connection it pauses after the short tolerance set in the deployment (at most 72 hours), and it cannot start at all until it has been verified once.
  • Networks that block outbound HTTPS to BCINexus (some hospital or lab networks) will stop devices from running.
  • Signing needs internet on your computer. Simulation does not.
  • A model file runs only on the devices it was exported for. Adding a board means exporting again for it.
  • A device can be removed once every 7 days. Over the allowance, the newest devices stop.

Security

  • Protection is software, not a hardware security chip. Someone with root access to a board can read that board’s key and so the models issued to it. They still cannot move a model to another board, alter a signed deployment, or exceed your device allowance.
  • Restoring an old backup of a board’s saved tolerance counter can give back at most one tolerance period.
  • Custom code runs with the service’s permissions: it can use the network and read the board, but can only write under /var/lib/bcinexus. Review code before you deploy it.
BCINexus Edge v1.0 · BCINexus Platform · 2026-09-15