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. Feeding real EEG? Read the epochs ingest contract first — epoching, baseline, filtering, sfreq discipline, axis conventions: Preparing epochs.

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.8.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.8.0
File Size Uploaded Provenance
nimbus_bci-0.8.0.tar.gz 1.4 MB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for nimbus-bci 0.8.0
File
nimbus_bci-0.8.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
nimbus_bci-0.8.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.8.0-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
nimbus_bci-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl CPython 3.13 CPython 3.13 macOS 10.13+ x86-64 Details
nimbus_bci-0.8.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
nimbus_bci-0.8.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.8.0-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
nimbus_bci-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl CPython 3.12 CPython 3.12 macOS 10.13+ x86-64 Details
nimbus_bci-0.8.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
nimbus_bci-0.8.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.8.0-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
nimbus_bci-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl CPython 3.11 CPython 3.11 macOS 10.9+ x86-64 Details

Total release size: 21.1 MB

Release files / nimbus_bci-0.8.0.tar.gz

Download URL nimbus_bci-0.8.0.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
4977ae5fac39ff8a64a118e217db4574a29d0a1bc7f2b0270a5811ebfd36f0a5
BLAKE2b-256 checksum
How to use checksums
145149e1f3aa4cd28a41e5760671ebbc36fe1d3cd424d2825e69ed15d90bdf49
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.8.0-cp313-cp313-win_amd64.whl

Download URL nimbus_bci-0.8.0-cp313-cp313-win_amd64.whl
Size 874.5 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
ccc21c02677494e4a830bc23474ecb2cec5217a747ab0fa92479aa39c51633d6
BLAKE2b-256 checksum
How to use checksums
2f523cbac348250eb60d226aec9c128000b30138d8f7e68f459ff6a59151ab74
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.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.8.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
8bf467f990cf47849a85e4dcea1f0cf2f17279b557dbdd7879e97f8c313d58e5
BLAKE2b-256 checksum
How to use checksums
91a884b825f3f2a2a0394d7bb08555f7c9c264c20f8b7d2f02c86ed9d9e78a22
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.8.0-cp313-cp313-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.8.0-cp313-cp313-macosx_11_0_arm64.whl
Size 950.7 kB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e123b71b49368fb12def108316131edba0ee2623aa191a169063c075bdced508
BLAKE2b-256 checksum
How to use checksums
8a36e476db160ec22473e26954413b3dfbedce4dac677d7490ff0857d6d4973b
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.8.0-cp313-cp313-macosx_10_13_x86_64.whl

Download URL nimbus_bci-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl
Size 959.4 kB
Tags CPython 3.13 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
5085e57f80f45b0d94ea0866dd95140056c7f58b892e15f2ffa7033e1ad4e44d
BLAKE2b-256 checksum
How to use checksums
e0283b752c70b46c422fe44f55d7746c763841f41674547c0a792703078b610c
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.8.0-cp312-cp312-win_amd64.whl

Download URL nimbus_bci-0.8.0-cp312-cp312-win_amd64.whl
Size 878.5 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
0390cbc2ad45e6525a174242293d525c1cdc9693e1247f699b345660f25fbd30
BLAKE2b-256 checksum
How to use checksums
c350eea98fa9daff8f54051d899f9c4bfadb710907e024f80578caed35767091
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.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 3.8 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
e67fd4ad805a87d9797abc0a732ebb5864da4b732e7f8a3bf79902b28f934dc0
BLAKE2b-256 checksum
How to use checksums
74fdfb90a488566ed8ec71b398403e4197e6d6e91d7659063a5a69e13578f0a9
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.8.0-cp312-cp312-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.8.0-cp312-cp312-macosx_11_0_arm64.whl
Size 955.3 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
f3618e5d4bea7b846ebb2d14a744f6f70869b15f7af2c737721710c039156168
BLAKE2b-256 checksum
How to use checksums
060d49ade6cc7687bcd49c78e03bb2a581d7abdee7f3eabed9f89749b4c954c8
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.8.0-cp312-cp312-macosx_10_13_x86_64.whl

Download URL nimbus_bci-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl
Size 962.5 kB
Tags CPython 3.12 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
61f6b47b5b1eecd6d5e6b62806b7a70823b035bb1c43ec2a432baa95864aa7d4
BLAKE2b-256 checksum
How to use checksums
cd6b7921017974bad89473a1f84de9d15a0a4c118f94114888e141973e5a7e03
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.8.0-cp311-cp311-win_amd64.whl

Download URL nimbus_bci-0.8.0-cp311-cp311-win_amd64.whl
Size 898.7 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
0b7d76ff5937d504bf159dfa5241cdf6ac68138f164f8790dbd29dabeac46fcf
BLAKE2b-256 checksum
How to use checksums
ae900cce92909886139bed855fbf3a796ecd6143a39e39ec441fe2df6d11c431
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.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL nimbus_bci-0.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 3.8 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
0d1839a7e3eca95f5ab39fe2e4a89ebee2e23c85e51f473dfeec077484b91af4
BLAKE2b-256 checksum
How to use checksums
512ef6158d00925c04f32a9743ce5b5de325109275f32468ac050a032a1666a2
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.8.0-cp311-cp311-macosx_11_0_arm64.whl

Download URL nimbus_bci-0.8.0-cp311-cp311-macosx_11_0_arm64.whl
Size 954.6 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c608e0028e508cd99c917f69e4d214ae60af8e7c5e3cabe267b6f7fa37e60e2c
BLAKE2b-256 checksum
How to use checksums
ec640a2420c25c310ddd576a6a6824103582f3f2d05b894c211b754e7deb13ab
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.8.0-cp311-cp311-macosx_10_9_x86_64.whl

Download URL nimbus_bci-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl
Size 981.1 kB
Tags CPython 3.11 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
e8690c92d133c29d7f7ff7d1b338fad73542b25376ba1bbbd920cdaf44733513
BLAKE2b-256 checksum
How to use checksums
e62648a54762ea1f26a3ed9b8d6dea18c2b9e4e7231ceb8e386672a3c7b0c7f4
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.8.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