Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
}
}
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
LICENSE_ID: ${{ secrets.LICENSE_ID }}
run: |
npm test
npm run package-ci
npm run lint
npm run tsc
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ keys.js

app/utils/pyodide/src
src/renderer/utils/pyodide/src

# Git worktrees
.worktrees/
56 changes: 56 additions & 0 deletions .llms/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# BrainWaves — Claude Code Rules

## Project Overview
BrainWaves is an Electron + React desktop application for running EEG experiments. It uses electron-vite for bundling, Redux + redux-observable for state management, and Pyodide (WASM) for in-app Python data analysis. Its primary usecase is making EEG data collection and analysis easy for students

## Background
This app is fairly complex in that it involves communicating with external EEG devices over bluetooth, with high precision and speed goals, and doing scientific computing within a frontier python-in-the-browser environment.
Reliability and visibility of these different sources of complexity is thus most important for developers.
The UI of the app should have a lighthearted and fun feel, since its target audience is students.
Redux Observables are hard to learn, but powerful. They help encapsulate complex temporally sensitive logic into functions. They should be maintained as an approach going forward, at least until a refactor is made.
A priority for this codebase is extensibility modularity and hackability. There are many features on the horizon such as swapping out hard-coded analysis for block-based programming, or even an embedd notebook environment. As such, effort should be taken not to hard-code things or cut corners by leaking abstractions.

## Stack
- **Runtime**: Electron (main) + React 18 (renderer)
- **Bundler**: electron-vite / Vite
- **State**: Redux Toolkit + redux-observable (RxJS epics)
- **Language**: TypeScript (strict)
- **Styling**: Semantic UI React + SCSS
- **Testing**: Jest
- **Linting**: ESLint + Prettier (single quotes, ES5 trailing commas)

## Key Directories
- `src/main/` — Electron main process
- `src/renderer/` — React renderer process
- `src/preload/` — Electron preload scripts
- `src/renderer/experiments/` — Lab.js experiment files
- `src/renderer/utils/pyodide/` — Pyodide WASM Python runtime

## Dev Workflow
```bash
npm run dev # Start dev server (patches deps first)
npm run build # Build all processes
npm test # Run Jest tests
npm run typecheck # TypeScript check (no emit)
npm run lint # ESLint
npm run lint-fix # ESLint + Prettier auto-fix
npm run package # Build + package for current platform
```

## Conventions
- Use TypeScript; avoid `any` unless strictly necessary
- Redux state changes go through RTK slices or typed actions via `typesafe-actions`
- Side effects belong in RxJS epics (`redux-observable`)
- Do not commit secrets or device credentials
- Keep Electron main/renderer separation strict — use preload IPC bridges

## Out of Scope
- Do not modify `src/renderer/utils/pyodide/src/` directly; it is managed by `InstallPyodide.js`
- Do not alter `electron-builder` publish config without confirming release intent

## LLM Context
Shared context for agents and developers lives in `.llms/`:
- `.llms/CLAUDE.md` — this file; stable conventions and architecture
- `.llms/learnings.md` — accumulated codebase insights from agents and developers

When you discover something non-obvious about the codebase (a gotcha, a hidden dependency, a tricky pattern), add it to `.llms/learnings.md` so future agents and developers benefit.
49 changes: 49 additions & 0 deletions .llms/learnings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# BrainWaves — Codebase Learnings

Accumulated insights from agents and developers working on this codebase.
Add entries here when you discover something non-obvious — gotchas, hidden dependencies, tricky patterns, debugging tips.

Format: brief heading + explanation + (optional) relevant file paths.

---

<!-- Add entries below this line -->

## React Router v6 + redux connect + class components: TypeScript inference gap

`withRouter<P>(Component: ComponentType<P & WithRouterProps>): ComponentType<P>`
works at runtime but TypeScript cannot infer `P` when the argument is a
`ConnectedComponent` (react-redux). Pragmatic solution: cast in `routes.tsx` with
a comment; or fully convert the class component to a functional component using
`useNavigate()` directly. See `src/renderer/utils/withRouter.tsx` and `routes.tsx`.

## connected-react-router → RouteChanged action pattern

Instead of listening to `@@router/LOCATION_CHANGE` in epics, dispatch
`ExperimentActions.RouteChanged(pathname)` from a `RouteChangeTracker`
component (uses `useLocation`). Epics then filter on this action. See
`src/renderer/epics/experimentEpics.ts` and
`src/renderer/components/RouteChangeTracker.tsx`.

## Tailwind v4 setup

Tailwind v4 uses `@tailwindcss/vite` plugin (no `tailwind.config.js`, no PostCSS
config). Add the plugin to the `renderer` section of `vite.config.ts` and
`@import 'tailwindcss'` at the top of the main CSS file.

## Shadcn/ui components live in src/renderer/components/ui/

Button, Card, Dialog — plus the `cn()` utility at `src/renderer/utils/cn.ts`.
Use these instead of Semantic UI equivalents.

## Pyodide v0.27.0 URL format change

v0.21.0 archive: `pyodide-build-{version}.tar.bz2`
v0.27.0+ archive: `pyodide-{version}.tar.bz2` (no "build-" prefix).
`InstallPyodide.js` must be updated accordingly when changing versions.

## sns.tsplot removed in Seaborn 0.10

`plot_conditions()` in `utils.py` used `sns.tsplot` which was removed in
Seaborn 0.10. Replaced with `plt.plot` + `fill_between` for mean ± SEM.
Seaborn is not imported at all now — matplotlib only for this function.
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@.llms/CLAUDE.md
@.llms/learnings.md
6 changes: 3 additions & 3 deletions internals/scripts/InstallPyodide.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import tar from 'tar-fs';
import url from 'url';
import bz2 from 'unbzip2-stream';

const PYODIDE_VERSION = '0.21.0';
const TAR_NAME = `pyodide-build-${PYODIDE_VERSION}.tar.bz2`;
const TAR_URL = `https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-build-${PYODIDE_VERSION}.tar.bz2`;
const PYODIDE_VERSION = '0.27.0';
const TAR_NAME = `pyodide-${PYODIDE_VERSION}.tar.bz2`;
const TAR_URL = `https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-${PYODIDE_VERSION}.tar.bz2`;
const PYODIDE_DIR = 'src/renderer/utils/pyodide/src/';

const writeAndUnzipFile = (response) => {
Expand Down
Loading
Loading