See inside every step of your EEG & fNIRS analysis.
Running a script gives you a figure at the end and no clue which step caused what. NeuroCode runs your MNE-Python script one step at a time in a real Jupyter kernel, then hands each step — and the real state of your data after it — to an LLM that explains what changed and why that step belongs there. The model writes with the actual result in front of it, not a guess at what the code probably did.
It also writes code from plain language and translates legacy EEGLAB / Homer3 (MATLAB) pipelines into MNE-Python.
A teaching tool for people learning EEG & fNIRS analysis. Bring your own Claude or Gemini key — everything else stays on your machine.
🌐 Project page · MIT licensed · Python 3.9+ · EEG · MEG · fNIRS
git clone https://github.com/ruixip/NeuroCode.git
cd NeuroCode
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
neurocode # opens http://127.0.0.1:8765The bundled examples use synthetic data, so they run instantly with nothing to download. Pick one from Load example…, hit Annotate & run, and click through the pipeline.
To turn the written explanations on, copy .env.example to .env and paste in
an ANTHROPIC_API_KEY or a GEMINI_API_KEY. It's optional — see
About the LLM for what runs without one.
CLI flags
neurocode --host 127.0.0.1 # bind address (default 127.0.0.1)
neurocode --port 8765 # port (default 8765)
neurocode --no-browser # don't open a browser window
neurocode --clear-cache # delete cached explanations and exit
Point it at a script — one you wrote, or one you inherited from a labmate who has since graduated — and find out what it actually does.
- Runs each step in a real Jupyter kernel, capturing stdout and matplotlib figures.
- Reports the data's real state after each step by introspecting the live objects (Raw / Epochs / Evoked; EEG, MEG and fNIRS channel types, tagged by modality).
- Semantic step grouping — an LLM groups statements by what they accomplish and labels each step, using blank-line and comment boundaries as hints. Falls back to structural grouping offline. Cached per script.
- Level-adaptive explanations: Novice / Intermediate / Expert.
- Ask follow-up questions on any step (multi-turn, scoped to that step).
- Click a step to highlight its source lines; a progress bar tracks the run.
- Write a new MNE script from a prompt, or tweak the current one in place.
- Diff view highlights exactly what was added and removed.
- One-click undo.
- Suggest next steps — research-goal-aware suggestions as clickable chips, for when you don't know what comes next.
- Paste or open a
.mscript. Recognisedpop_*/hmrR_*calls are detected by regex and shown as confidence-coloured chips before translation. - The translation is grounded in a curated function-mapping knowledge base
(
neurocode/knowledge/*.json) rather than free improvisation, and flags calls it can't map instead of guessing. - An in-app reference viewer (📚 button) browses the EEGLAB↔MNE and Homer3↔MNE tables with confidence badges, caveats and workarounds.
Local file import: 📂 opens a local .py / .m file, read client-side by
the browser — no upload. Legacy .m files open pre-filled in the translator.
The explanations, the code generation and the legacy translation are all LLM-driven, but the model is kept on a short leash and you own the key.
Grounded in a real run. Every explanation is generated after the step executes, with the introspected data state in the prompt. Translation is anchored to the mapping tables above.
Bring your own key. NeuroCode auto-detects whichever is present:
| Env var | Provider | Default model |
|---|---|---|
ANTHROPIC_API_KEY |
Claude | claude-haiku-4-5 |
GEMINI_API_KEY / GOOGLE_API_KEY |
Google Gemini | gemini-2.5-flash |
If both are set, Anthropic wins. The active provider is printed to the terminal on startup.
Override the model with NEUROCODE_MODEL — it is applied only when the model
name matches the active provider (claude* for Anthropic, gemini* for
Gemini), so a stale override left over from the other provider is ignored rather
than sent to the wrong API. Note that free Gemini tiers have low per-minute
limits, so a multi-step annotate run can rate-limit; the cache fills in the
remaining steps across re-runs.
Exactly what leaves your machine. Your source code, plus a short JSON summary of the data's shape — sampling rate, channel count and the first few channel names, channel types, filter band, duration, epoch count. The recordings themselves are never sent. There is no NeuroCode server, no account, and no other network destination.
No key? It still works. Without one, NeuroCode runs every step, plots every figure and reports the real data state — you just get templated text instead of written explanations. The kernel half needs no LLM at all.
Cached, so you don't pay twice. Explanations and step segmentations are cached on disk keyed by (model, level, code, data state), so a re-run — or re-viewing a step — costs no API call and is instant.
- Location:
~/.neurocode/cache.json(override withNEUROCODE_CACHE) - Size: ~1–2 KB per entry, hard-capped at 500 entries LRU (
NEUROCODE_CACHE_MAX) - Clear it:
neurocode --clear-cache
Errors and offline fallback text are never cached.
neurocode/
cli.py neurocode command → launches the local server + browser
server.py FastAPI + /ws WebSocket (annotate / generate / ask / suggest /
translate actions) and /api/examples, /api/mapping
chunker.py split a script into statements / structural steps (AST-based)
kernel.py Jupyter kernel wrapper: run steps, capture stdout + figures
introspect.py in-kernel report of EEG/MEG/fNIRS object state as JSON
llm.py provider-thin LLM layer: explain_step, generate_code,
answer_question, suggest_next_steps, segment_steps,
detect_legacy_calls, translate_legacy_code (BYO key)
cache.py on-disk LRU cache of explanations + segmentations
knowledge/ curated EEGLAB↔MNE and Homer3↔MNE mapping tables (JSON)
static/ vanilla-JS UI: pipeline, AI bar, translate + mapping modals
examples/ synthetic demos: preprocessing, epoching, evoked, TFR, fNIRS
docs/ project page + mapping methodology notes
Three design choices keep it cheap, private and hackable:
- No hosted compute — everything runs on
localhost. - Bring your own key — and it runs offline, with templated text, without one.
- Reuses the scientific Python display stack via a real Jupyter kernel, rather than reimplementing plotting or object introspection.
The LLM layer is deliberately thin — the raw Anthropic and Google SDKs behind a shared streaming helper, not an agent framework — so adding a provider (or a local model) means writing one function.
| Example | Covers |
|---|---|
preprocessing.py |
filtering, re-referencing, resampling |
epoching.py |
events → trials |
evoked_erp.py |
averaging + topomap |
time_frequency.py |
Morlet power |
fnirs_preprocessing.py |
optical density, Beer–Lambert, scalp coupling index |
All synthetic — no downloads, instant to run.
NeuroCode is a working MVP under active development. Where it stands today:
- Modalities. EEG and MEG object introspection is solid. fNIRS covers the
standard preprocessing chain (OD → SCI → Beer–Lambert → filter); GLM-based HRF
estimation and short-channel regression, which need the separate
mne-nirspackage, are not wired in yet. - Time-frequency objects run and plot, but don't yet get a state badge — introspection currently covers Raw / Epochs / Evoked.
- Translation is v0. It has been exercised on short hand-written
EEGLAB / Homer3 snippets rather than full lab pipelines. The mapping tables
(12 EEGLAB entries, 10 Homer3/fNIRS entries) are documented starting
hypotheses with explicit confidence levels — see
docs/eeglab_mne_mapping_methodology.mdfor how they were built and how to extend them. Domain-expert review is actively wanted here.
Next up: data grounding — reading your real .fif / .edf / .set /
.snirf so that explanations and generated code use your actual sampling rate,
channels, montage and events.
See CHANGELOG.md for the detailed history.
This is early enough that feedback genuinely changes what gets built next. What's confusing, what's missing, and what would make you reach for it while working with your own data?
Particularly useful: EEGLAB / Homer3 users willing to check the mapping tables, and anyone teaching EEG or fNIRS analysis who can say where the explanations land wrong.
Development setup:
pip install -e ".[dev]" # adds ruff + pytestMIT — see LICENSE.
Built on MNE-Python.