Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8c5c616
Standardize repo layout: AGENTS.md, settings, LF line endings, CHANGELOG
VisLab Sep 24, 2026
8be565a
Replace hardcoded data paths in the two general example scripts
VisLab Sep 24, 2026
d816494
Remove the three ESS example scripts
VisLab Sep 24, 2026
762e415
Move documentation from gh-pages to a Sphinx site in docs/
VisLab Sep 25, 2026
179a3dc
Document building and publishing the docs in README.md
VisLab Sep 26, 2026
5f6e745
Use pip, not uv, in the local docs setup instructions
VisLab Sep 26, 2026
b9db4f3
Show Windows and Linux/macOS docs setup separately in README.md
VisLab Sep 26, 2026
7bb8d88
Bind the local docs server to 127.0.0.1 in README.md
VisLab Sep 26, 2026
bea47ca
Render MATLAB help text in the API docs as preformatted text
VisLab Sep 26, 2026
3d7b37b
Fix file/function name mismatches
VisLab Sep 26, 2026
229db5b
Address Copilot review of PR 38
VisLab Sep 26, 2026
7bc5473
Add root GPL license and licensing table; remove BLASST
VisLab Sep 27, 2026
2b01182
Point the example scripts at examples/data; add Zenodo DOI badge
VisLab Sep 27, 2026
9003d45
Address second Copilot review of PR 38
VisLab Sep 27, 2026
e57910f
Fence Claude's reads to the working directories
VisLab Sep 27, 2026
08c2f81
Address third Copilot review of PR 38
VisLab Sep 28, 2026
1353c57
Fix off-by-one in the robust reference iteration limit
VisLab Sep 28, 2026
a7477ec
Remove the read fence from .claude/settings.json
VisLab Nov 3, 2026
79bbe0c
Standard assistant settings and the two-import CLAUDE.md
VisLab Nov 4, 2026
fed1122
Add .editorconfig and a CI check that fails on CRLF
VisLab Nov 5, 2026
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
23 changes: 23 additions & 0 deletions .claude/rules/status_conduct.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
paths:
- ".status/**"
---

# Working in .status/

- `.status/` is gitignored: the only copy is on this machine. Never delete,
move, or rewrite a file here without asking first. Appending is fine.
- Every markdown file written here opens with a `For humans:` summary - three
or four sentences at the very top: what the file is and what a person needs
to take from it.
- Nothing new is created at the `.status/` root. New material goes in
`plans/`, `prompts/`, `notes/`, or `scratch/`.
- Only `plans/` and `prompts/` are edited in place. `notes/` is write-once.
`decisions.md` is append-only - never rewrite an entry.
- Temporary scripts, experiments, and one-off test files go in
`.status/scratch/` - never the repository root. `scratch/` may hold any
file type and is deleted unread; everywhere else is markdown only.
- Do not read `archive/` unless a file is named for you.
- Filenames: lowercase ASCII, `_` as separator. Notes are
`YYYY-MM-DD_slug.md` (date first); plans and prompts are `slug.md` - no
date, no status word in the name.
41 changes: 41 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(python --version)",
"Bash(unzip -l *)",
"Bash(python -m sphinx *)",
"Bash(python docs/patch_matlabdomain.py)",
"Bash(git status *)",
"Bash(git log *)",
"Bash(git diff *)",
"Bash(git branch)",
"Bash(git branch --show-current)",
"Bash(git branch -a)",
"Bash(git branch -r)",
"Bash(git branch -vv)",
"Bash(git ls-files *)"
],
"ask": [
"Bash(matlab -batch *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git checkout -- *)",
"Bash(git restore *)",
"Bash(git stash *)"
],
"deny": [
"Read(.env)",
"Read(.envrc)",
"Bash(rm -rf *)",
"Bash(rm -r *)",
"Bash(git push)",
"Bash(git push *)",
"Bash(git reset --hard *)",
"Bash(pip install *)",
"Bash(python -m pip install *)",
"Bash(curl *)",
"Bash(wget *)"
]
}
}
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Editor defaults for every file in this repository, including gitignored
# working files that git never sees. LF only on every OS: .gitattributes
# enforces it at commit time, this file at edit time.
#
# Trailing whitespace is trimmed in Markdown too: write a hard line break as
# a trailing backslash, not two trailing spaces (mdformat converts the
# two-space form to the backslash form anyway).
#
# This is the floor. Add sections for particular file types (indent rules,
# for example), but do not override the [*] keys.
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
46 changes: 46 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Set default behavior to automatically normalize line endings to LF
* text=auto eol=lf

# Explicitly declare text files you want to always be normalized and converted to LF on checkout
*.xml text eol=lf
*.mediawiki text eol=lf
*.tsv text eol=lf
*.md text eol=lf
*.rst text eol=lf
*.txt text eol=lf
*.m text eol=lf
*.tex text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.svg text eol=lf
*.css text eol=lf
*.js text eol=lf
*.html text eol=lf

# Denote all files that are truly binary and should not be modified
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
*.set binary
*.fdt binary
*.gz binary
*.tar binary
*.mp3 binary
*.mp4 binary
*.mov binary
*.avi binary
*.exe binary
*.dll binary
*.so binary
*.dylib binary
*.class binary
*.jar binary
*.war binary
18 changes: 18 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# EEG-Clean-Tools

**`AGENTS.md` at the repository root is the instruction set for this project.
Read it before answering, and follow it.**

This file is a pointer and duplicates nothing. One source, several pointers: a
rule stated in two files is a rule that will disagree with itself.

Path-specific instructions live in `.github/instructions/*.instructions.md`
and load automatically when the files being worked on match their `applyTo`
glob - for example, `status_conduct.instructions.md` applies under `.status/`.
Nothing needs to reference them; this note exists so a reader knows they are
there.

Machine-specific facts - interpreter, local paths, cache locations - are in
`.status/local-environment.md`, which is gitignored: read it when it is there
and ignore its absence when it is not. No committed file in this repository
may contain a local path or a drive letter.
22 changes: 22 additions & 0 deletions .github/instructions/status_conduct.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
applyTo: ".status/**"
---

# Working in .status/

- `.status/` is gitignored: the only copy is on this machine. Never delete,
move, or rewrite a file here without asking first. Appending is fine.
- Every markdown file written here opens with a `For humans:` summary - three
or four sentences at the very top: what the file is and what a person needs
to take from it.
- Nothing new is created at the `.status/` root. New material goes in
`plans/`, `prompts/`, `notes/`, or `scratch/`.
- Only `plans/` and `prompts/` are edited in place. `notes/` is write-once.
`decisions.md` is append-only - never rewrite an entry.
- Temporary scripts, experiments, and one-off test files go in
`.status/scratch/` - never the repository root. `scratch/` may hold any
file type and is deleted unread; everywhere else is markdown only.
- Do not read `archive/` unless a file is named for you.
- Filenames: lowercase ASCII, `_` as separator. Notes are
`YYYY-MM-DD_slug.md` (date first); plans and prompts are `slug.md` - no
date, no status word in the name.
95 changes: 95 additions & 0 deletions .github/workflows/deploy-docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Deploy Documentation

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

# Read-only by default. Only the deploy job, which runs only on pushes to
# master, gets the Pages and OIDC write permissions; the build job runs code
# from the branch (docs/conf.py, the patch script) and stays read-only.
permissions:
contents: read

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
pages: read # actions/configure-pages reads the Pages site settings
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- name: No CRLF line endings in tracked files
run: |
if git ls-files --eol | grep -E '^i/(crlf|mixed)' | grep -v 'attr/-text'; then
echo "CRLF found in the files above; .gitattributes requires LF."
exit 1
fi

- name: Install uv
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
python-version: '3.10'
enable-cache: true
cache-dependency-glob: "**/pyproject.toml"

- name: Create virtual environment
run: |
uv venv --clear .venv
echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH

- name: Install dependencies
run: uv pip install -e ".[docs]"

- name: Patch sphinxcontrib-matlabdomain
run: python docs/patch_matlabdomain.py

- name: Configure Git for GitHub Pages
run: |
git config user.name github-actions
git config user.email github-actions@github.com

- name: Build documentation
run: |
sphinx-build -b html docs docs/_build/html

- name: Setup Pages
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6

- name: Upload artifact
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
with:
path: ./docs/_build/html

#------------------------------------------------
# Deploy Job: Deploys the built site
#------------------------------------------------
deploy:
# This job depends on the 'build' job completing successfully
needs: build
# Only deploy when pushing to master, not on pull requests
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
permissions:
pages: write
id-token: write
runs-on: ubuntu-latest

# Specify the deployment environment
environment:
name: github-pages
# The URL will be automatically set by the deployment step's output
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
# This is the official action for deploying the artifact to GitHub Pages
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5
26 changes: 25 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
*.asv
*.asv

# Personal per-repo Claude Code notes (imports .status/local-environment.md)
CLAUDE.local.md

# Personal per-repo settings (absolute paths, claudeMdExcludes)
.claude/settings.local.json

# Real tokens and machine values; .env.example is the committed documentation
.env

# Working notes, plans, prompts, and decision records. Deliberately NOT
# committed: these repos are public and .status/ holds half-formed thinking.
# The consequence is that it lives on one machine only and is absent from
# fresh clones and from `claude --worktree` worktrees.
.status/

# Documentation build and its Python toolchain
docs/_build/
.venv/
__pycache__/
*.egg-info/

# Output of the example scripts
PrepPipeline/examples/output/
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,

"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": false
}
69 changes: 69 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# EEG-Clean-Tools

Purpose: the PREP pipeline - standardized early-stage EEG preprocessing (boundary handling, detrending, line-noise removal, robust average referencing, bad-channel detection and interpolation, reporting) as a MATLAB toolbox and an EEGLAB plugin.

Not in scope: EEGLAB itself, which PREP runs inside and depends on, and the downstream analysis PREP deliberately leaves open (final high-pass filtering, ICA).

## Commands

Test framework: none. There is no test suite. Do not add a suite as a side effect of other work.

- Smoke check (no EEGLAB needed): `matlab -batch "addpath(genpath('PrepPipeline')); disp(getPrepVersion())"` - prints the version string, for example `PrepPipeline0.57.0`
- Run standalone: add `PrepPipeline` and its subfolders to the MATLAB path, then `[EEG, params, computationTimes] = prepPipeline(EEG, params)` on an EEGLAB `EEG` structure with channel locations. Needs EEGLAB and the Signal Processing Toolbox on the path.
- Run as a plugin: unzip `EEGLABPlugin/PrepPipeline<version>.zip` into EEGLAB's `plugins/` folder; the menu entry is Tools -> Run PREP pipeline.
- Check the plugin zip: `unzip -l EEGLABPlugin/PrepPipeline<version>.zip`
- Install the docs toolchain: `python -m venv --clear .venv`, activate it, then `python -m pip install -e ".[docs]"` and `python docs/patch_matlabdomain.py` (required after every install of `sphinxcontrib-matlabdomain`; it fixes a Sphinx 7+ incompatibility in that package). Locally, use pip and the activated `.venv`, never `uv` or `uvx`: uv misbehaves on Windows. The GitHub Actions workflows use uv, and that stays.
- Build docs: `python -m sphinx -b html docs docs/_build/html` - `.github/workflows/deploy-docs.yaml` runs the same build and publishes it to GitHub Pages on pushes to `master`

## Layout

- `PrepPipeline/` - entry points: `prepPipeline.m`, `pop_prepPipeline.m` (EEGLAB GUI wrapper), `prepPostProcess.m`, `prepReport.m`, `publishPrepReport.m`, `eegplugin_prepPipeline.m` (EEGLAB menu registration)
- `PrepPipeline/utilities/` - the algorithms (`removeTrend`, `cleanLineNoise`, `performReference`, `findNoisyChannels`, defaults, version); `chronux_2_modified/` is vendored third-party code (GPL v2; see the licensing table in `README.md`)
- `PrepPipeline/reporting/` - report and collection-statistics functions
- `PrepPipeline/interface/` - the EEGLAB parameter GUIs
- `PrepPipeline/derived/`, `PrepPipeline/examples/`, `PrepPipeline/extracted/` - scripts built on the pipeline
- `EEGLABPlugin/` - the released plugin as a zip
- `docs/` - Sphinx source for the documentation site (MyST markdown and `.rst`); images in `docs/_static/images/`. `pyproject.toml` exists only to declare the docs toolchain.
- `CHANGELOG.md` - release history
- `.status/` - working notes. Gitignored; local to each machine.

## Conventions that differ from defaults

- **ASCII only** in prose, code, comments, and filenames: `-` not em or en dashes, `->` not arrows, `...` not an ellipsis character, straight quotes. Exception: genuine data (author names, dataset titles, recorded API responses) keeps whatever characters it actually contains.
- Markdown headers are sentence case: capitalize only the first word, proper nouns, and acronyms (PREP, EEG, EEGLAB, MATLAB).
- MATLAB: camelCase for functions. The file name must match the function name, so `.m` files keep their mixed case.
- The default branch is `master`, not `main`.

## Rules that are easy to get wrong

- The version exists in three places that must agree: `PrepPipeline/utilities/getPrepVersion.m` (the change log that `getPrepVersion` returns), the zip name under `EEGLABPlugin/`, and `CHANGELOG.md`. Change all three together.
- Do not reformat, lint, or ASCII-clean vendored code under `PrepPipeline/utilities/chronux_2_modified/`.
- `docs/api.rst` pulls each function's help text from the comment block right after its `function` line. `docs/conf.py` shows that text preformatted, exactly as MATLAB `help` prints it, so write help for `help`, not as reStructuredText. Help placed above the `function` line does not appear there, though MATLAB `help` still finds it. Functions at the root of `PrepPipeline/` need `.. mat:currentmodule:: .` before their `mat:autofunction` directives.
- Do not change the signature of an entry-point function without discussion; EEGLAB and user scripts call them directly, and `pop_prepPipeline` writes the call into EEGLAB history.

## Related repositories

Referred to by name; none is vendored here.

- `eeglab` - the MATLAB toolbox PREP runs in, required at runtime.
- `hed-matlab` - the model for this repository's layout and documentation setup.

## Where the thinking lives

`.status/` is gitignored, so it exists only on the machine that wrote it and never in a fresh clone or worktree.

- `.status/README.md` - the index. Read this first; it lists what is active.
- `.status/decisions.md` - why things are the way they are. Read before proposing structural changes. Append entries; never rewrite one.
- `.status/plans/*.md` - active plans. Check the `Status:` header and the `[ ]` / `[x]` markers before starting work.
- `.status/local-environment.md` - this machine's paths, interpreter, and quirks. Tool-agnostic. Never copy its contents into a committed file.
- IMPORTANT: do not read `.status/archive/` unless a file is named for you. Nothing new is created at the `.status/` root.

## Working agreements

- IMPORTANT: every file written to `.status/` opens with a `For humans:` summary - three or four sentences, at the very top: what the file is and what a person needs to take from it. The same applies to a long answer in a session: lead with the conclusion.
- IMPORTANT: temporary scripts, experiments, and one-off test files go in `.status/scratch/` - **never the repository root**. Delete them when the experiment ends; anything in `scratch/` may be deleted unread.
- IMPORTANT: never delete or rewrite a file under `.status/` without asking first. Appending is fine.
- For a change spanning more than three files, write a plan to `.status/plans/` and stop for review before editing.
- When you are guessing about an external API or data format, say so explicitly rather than assuming.
- Show evidence, not assertions: the command you ran and its actual output.
- Do not commit, push, or create branches unless asked.
Loading
Loading