Skip to main content

nimbus-bci

Nimbus Personalizer — Bayesian personalization head for frozen neural EEG embeddings.
Plug any frozen trunk that emits encode(X) → Z, adapt online with a Nimbus head, ship apps on BrainState — without owning or retraining the encoder.

0.6 product shape: the Personalizer surface — cheap online adaptation (~8–10× cheaper than batch refit, ~22–131× cheaper than trunk retraining at matched n), portable profiles, and paradigm recipes (MI · P300 · Riemannian).

Also ships sklearn-compatible heads for classical feature pipelines (CSP, Riemann, …): Bayesian LDA / QDA / Softmax, plus NimbusSTS (EKF latent state + point-estimated emissions). Those heads power Personalizer and can be used alone.

Docs · Personalizer · API reference · PyPI · Contact

Install

pip install nimbus-bci
# optional: pip install nimbus-bci[softmax]   # JAX Softmax head
# optional: pip install nimbus-bci[riemann]   # pyRiemann pipelines
# optional: pip install nimbus-bci[mne]       # MNE helpers
# optional: pip install nimbus-bci[train]     # torch trunk-arm trainers (LoRA / FT)
# optional: pip install nimbus-bci[viz]       # matplotlib plotting helpers
# optional: pip install nimbus-bci[all]       # everything above

From source: pip install -e ".[all]" after cloning.

Upgrading from 0.5? See Migration notes in CHANGELOG.md (ships in the sdist; also linked from docs.nimbusbci.com).

5-minute quickstart

Run the example (no external data needed):

python examples/quickstart.py

Or follow along:

import numpy as np
from nimbus_bci import Personalizer, wrap

# 1. Wrap any frozen trunk (EEGNet, REVE, ...) — here a random projection.
rng = np.random.default_rng(42)
proj = rng.standard_normal((6, 16))
enc = wrap(lambda X: X @ proj, model_id="toy", embedding_dim=16)

# 2. Fit a Bayesian head on ~30 calibration trials.
#    for_deployment = strict gating + LDA + minimal params (the common case).
#    For research/experimentation: Personalizer.for_research(enc, classes, ...).
#    For classical features (no encoder): Personalizer.for_features(classes).
#    To PIN the accept rate for your trunk (default-gate accept rates span
#    7-78% across trunks), fit + calibrate the gate in one call:
#    adapter.fit_calibrated(X_cal, y_cal, X_val, y_val, target_accept=0.7)
adapter = Personalizer.for_deployment(enc, ["left_hand", "right_hand"],
                                       paradigm="motor_imagery")
adapter.fit(X_cal, y_cal)

# 3. Predict → BrainState with trial rejection.
states = adapter.predict(X_test)         # list[BrainState]
accepted = [s for s in states if not s.rejected]  # confident trials
# s.intent, s.confidence, s.uncertainty, s.rejected, s.rejection_reason

# 4. Adapt online (exact conjugate update — no retraining).
adapter.partial_fit(X_new, y_new)

# 5. Save / load.
adapter.save("profile"); loaded = Personalizer.load("profile", encoder=enc)

The three regimes

# A. Classical features (CSP log-variance, tangent space, hand-crafted) —
#    no encoder, features go straight to the Bayesian head.
p = Personalizer.for_features(["left", "right"]).fit(X_csp, y)

# B. Frozen deep trunk (EEGNet, foundation model) — embeddings → head,
#    strict trial gating out of the box.
p = Personalizer.for_deployment(enc, ["left", "right"]).fit(X_cal, y_cal)
states = p.predict(X_test)          # BrainState per trial, rejected flagged

# C. Riemannian geometry & P300 (OAS / xDAWN tangent space) —
#    weak-trunk / raw epochs; for_riemann defaults to label-free geodesic
#    tracking (tracking_alpha=0.05). Opt out with tracking_alpha=0.0.
p = Personalizer.for_riemann(["left", "right"]).fit(X_cal, y_cal)
# Or for P300 spellers (tracking opt-in; recommend α=0.05 when enabling):
# Personalizer.for_p300(["NonTarget", "Target"], tracking_alpha=0.05)
p.adapt(epoch)                      # label-free reference update (0 labels needed!)

# D. Streaming adaptation loop — predict, optionally partial_fit on new
#    labels; the conjugate head update is exact and cheap (no retraining).
#    Reference: examples/middleware_streaming_adaptation.py
for trial in stream:
    state = p.predict(trial)                # BrainState
    if label_available(state):
        p.partial_fit(trial, label)         # ~1/30-1/131 the wall cost of retraining

Regime A/B/C are the shipped surface. A governed session runtime (drift gates, attribution, label budgets, quarantine) with subconscious error-potential self-supervision is in research and will ship separately.

The full parameter surface (user=, preset=, head choice) via direct construction — anything that maps inputs to embeddings (n, d) plugs in; Nimbus does not own DL architectures:

adapter = Personalizer(
    encoder=enc, head="lda", user="subject_001",
    classes=["left", "right"], preset="strict",
)

Full walkthrough with copy-paste synthetic data: Quickstart.

Optional shortcuts for common external trunks: wrap_eegnet, and from nimbus_bci.middleware.adapters import wrap_braindecode (see encoder contract).

Examples in this repo: middleware_personalizer.py, middleware_streaming_adaptation.py, middleware_geometry_gateway.py, middleware_mi_session.py, middleware_braindecode.py, middleware_reve.py, middleware_recommend_adapt.py.
Bench EEGNet demo (repo-only, needs nimbusbench[dl]): nimbusbench/scripts/middleware_eegnet.py.

When to adapt (thin helper)

Optional mean-shift check before spending labels on partial_fit. You choose the threshold tau.

dec = adapter.recommend_adapt(X_stream, tau=your_tau)  # stay vs stream update
if dec.should_adapt:
    adapter.partial_fit(X_lab, y_lab)

Trial rejection (BrainState.rejected / need_more_data) is a different gate — accept/reject the intent for the app.
Details: BrainState · recipe: examples/middleware_recommend_adapt.py.

A governed adaptation session — drift gates, label budgets, quarantine, and rollback — is under research and will ship as a separate release once its evidence matures.

Classical heads (CSP / features)

Same Bayesian heads without an encoder — inputs are already features:

from nimbus_bci import NimbusLDA

clf = NimbusLDA()
clf.fit(X_train, y_train)
proba = clf.predict_proba(X_test)
clf.partial_fit(X_new, y_new)

Also: streaming (StreamingSession), active learning (CalibrationSession), MNE helpers, optional Riemann pipelines. See docs.nimbusbci.com and examples/e2e_mne_csp_nimbus.py.

Head Role
NimbusLDA / NimbusQDA Conjugate Bayesian LDA/QDA
NimbusSoftmax Polya–Gamma VI (optional JAX)
NimbusSTS EKF latent-state / drift (EKF on z; point W/H/b)

Working with precomputed embeddings

If your pipeline already computed embeddings — frozen backbone → per-trial embeddings (N, F) — declare the contract so the Personalizer consumes X directly instead of re-encoding it through the attached trunk:

from nimbus_bci import Personalizer, wrap

adapter = Personalizer(
    encoder=wrap(module),        # attached for model_id / lineage — never called
    x_kind="embeddings",         # every X below is ALREADY the encoder output
    head="softmax",
    classes=["left", "right"],
)
adapter.fit(Z_cal, y_cal)                        # (N, F) — head + transforms fit directly
adapter.partial_fit(Z_stream, y_stream)          # online head updates
adapter.adapt(Z_stream, y_stream, level="head")  # supervised head adaptation

The rule: trunk adaptation needs raw encoder inputs. LoRA / BaLoRA / fine-tuning backpropagate through the trunk, and precomputed embeddings have no gradient path to trunk weights — so adapt(..., level="trunk"), adapt_trunk(...), adapt_async(...), fit_tent(...), trunk MC sampling, and Riemannian reference tracking (update_riemann_reference(...)) raise PersonalizerInputError under x_kind="embeddings". To adapt the trunk, feed raw epochs with the default x_kind="epochs". x_kind="embeddings" with encoder=None is also legal — that is the classical feature-space flow (Personalizer.for_features(...)).

Profiles round-trip the contract: export_profile() records x_kind and the observed embed_dim in UserProfile.meta; from_profile(...) restores them, refuses an x_kind mismatch, and validates the feature dim of the next fit against the recorded embed_dim.

Evidence

Public Personalizer story (heads, cost vs fine-tune, multi-trunk / REVE):
Evidence · Overview.

License

Two-track proprietary license — see the LICENSE.txt shipped with the package (and on PyPI). Non-commercial use is free under the Non-Commercial terms; commercial use requires a paid license. Contact: hello@nimbusbci.com.

Contributing & security

Licensees with source access: follow the repository CONTRIBUTING.md and SECURITY.md. Report vulnerabilities privately to hello@nimbusbci.com — do not open a public issue.

Metadata

Release files for nimbus-bci 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nimbus-bci 0.7.0
File Size Uploaded Provenance
nimbus_bci-0.7.0.tar.gz 1.3 MB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for nimbus-bci 0.7.0
File
nimbus_bci-0.7.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
nimbus_bci-0.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
nimbus_bci-0.7.0-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
nimbus_bci-0.7.0-cp313-cp313-macosx_10_13_x86_64.whl CPython 3.13 CPython 3.13 macOS 10.13+ x86-64 Details
nimbus_bci-0.7.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
nimbus_bci-0.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
nimbus_bci-0.7.0-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
nimbus_bci-0.7.0-cp312-cp312-macosx_10_13_x86_64.whl CPython 3.12 CPython 3.12 macOS 10.13+ x86-64 Details
nimbus_bci-0.7.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
nimbus_bci-0.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64, Linux glibc 2.17+ x86-64 Details
nimbus_bci-0.7.0-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
nimbus_bci-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl CPython 3.11 CPython 3.11 macOS 10.9+ x86-64 Details

Total release size: 20.4 MB

Release files / nimbus_bci-0.7.0.tar.gz

Download URL nimbus_bci-0.7.0.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
4b87e6af74a81f31ff9d15455f630bca97d14b79108c45586eef40e9e970af22
BLAKE2b-256 checksum
How to use checksums
0c013f9e2d02a485e54b9e09c908f2d5ff5a5106d294181fd03ed6338de47f53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp313-cp313-win_amd64.whl

Download URL nimbus_bci-0.7.0-cp313-cp313-win_amd64.whl
Size 825.4 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
a6c5f322aa2b6c78ec2c73cf579161d702673674ac1f078b0f0816ba70597dc7
BLAKE2b-256 checksum
How to use checksums
4f71a1fe58f439bc0a897668fac6bec5711454b6221518660ba0638d1bd24159
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 3.7 MB
Tags CPython 3.13 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
2393965a935946eba8a5fa8567ff6ca24d63f2b66858942abb5c13b247f2e716
BLAKE2b-256 checksum
How to use checksums
8aa1c3f2547e2a85ed55f630999da082820c7e3029d9860c86666f93e6676d33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp313-cp313-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.7.0-cp313-cp313-macosx_11_0_arm64.whl
Size 901.9 kB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e4606a40146d1344d4c8ee8c479774c0e6e1a531b0e1093654f1b3fff957c6f0
BLAKE2b-256 checksum
How to use checksums
2e9294bf612466e7dbc272f1de6ab2266a710386c0c5c85b56fef9e119fd8fbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp313-cp313-macosx_10_13_x86_64.whl

Download URL nimbus_bci-0.7.0-cp313-cp313-macosx_10_13_x86_64.whl
Size 910.6 kB
Tags CPython 3.13 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
9ec6ecd3d2ac5450ff534c3c846686989692d505f8c80f5a1d07d3f640fab0e0
BLAKE2b-256 checksum
How to use checksums
12a3aae91e0b0092383d8fb27323b9efc98a16a38c7a4e9953bad6bc7be26ca7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp312-cp312-win_amd64.whl

Download URL nimbus_bci-0.7.0-cp312-cp312-win_amd64.whl
Size 829.5 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
9f8de9c235a4ef989a95587e9cfc197e7958b6c545e7ce3efe356a8ab77988b5
BLAKE2b-256 checksum
How to use checksums
63c827e2d17a26913a0bddb9294f17a2175424eb0295966acfeac437d8efec15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 3.7 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
b706ed62009ef68aa666423685331a6164fb458a2fc5e95e8c657726b30ccde0
BLAKE2b-256 checksum
How to use checksums
5f8ae47a9c206ab1b46cdd21dacb13392a50af088b9670824e09ea0c98b64c1d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp312-cp312-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.7.0-cp312-cp312-macosx_11_0_arm64.whl
Size 906.5 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
05187363be6e5e0e6bc83d09280c6db7fb4a81d7595ad35e6238bceb6bd04b6a
BLAKE2b-256 checksum
How to use checksums
3462148b9e4e943f7a617651ef85d800ddcd4d82343dee931d5cd8988b07a3a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp312-cp312-macosx_10_13_x86_64.whl

Download URL nimbus_bci-0.7.0-cp312-cp312-macosx_10_13_x86_64.whl
Size 913.7 kB
Tags CPython 3.12 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
aeb80ccf6ac8fc46f285eb93377c5c0fb6f6776743428d01f33773124026e60a
BLAKE2b-256 checksum
How to use checksums
085aa6c65c935270615831c5199a0d097cfb2d37219a6c31cc0a63cf78ca2fff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp311-cp311-win_amd64.whl

Download URL nimbus_bci-0.7.0-cp311-cp311-win_amd64.whl
Size 849.7 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
82bf058476d4f0a1e4506497e381b8a9a0fd18be05e9350eaf8a0cea3bc180c9
BLAKE2b-256 checksum
How to use checksums
a7afe92b8c06205d3963822f928203284dd8845c00d7a508c3656ad9c290210e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 3.7 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
1a1c89bbf50af4b0c535346363ede644c81b1ff78d0c0eb1c3e5433b16d5afea
BLAKE2b-256 checksum
How to use checksums
b0a3062165bc533d80a132d7412b261419584d6f4cb011f8b2be8b9844f3b2ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp311-cp311-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.7.0-cp311-cp311-macosx_11_0_arm64.whl
Size 905.8 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
199bd6f11ffbd3a2b7704a21c7757069b0922a219587ecd26eb33b8ce08cbe7f
BLAKE2b-256 checksum
How to use checksums
b26bce2d331c6c9ebbaa0783215b56f1dec4cf38b1caa35457cea1a352ee2072
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nimbus_bci-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl

Download URL nimbus_bci-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl
Size 932.2 kB
Tags CPython 3.11 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
84fbe8323a9a4d6e46d9b573ca4b83d4020bdb0fad0c3ccac452aed2733148b8
BLAKE2b-256 checksum
How to use checksums
a5fee4d6c93e254f4bc98080e2a8569081a0d69b2231b7fe3c6308629de3ed31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for nimbus-bci 0.7.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page