Add agent-friendly EEGPrep CLI - #176
Conversation
[Parity] Add core matrix contracts
# Conflicts: # .notes/implementation-notes.html
Complete clean_rawdata and FIRFilt parity
…tics [ICLabel] Complete viewprops diagnostics parity
…ompletion' into phase/160-dipfit-source-parity # Conflicts: # .notes/implementation-notes.html
Add standalone DIPFIT source-localization parity
…ompletion' into phase/161-study-pac-limo # Conflicts: # .notes/implementation-notes.html
Implement STUDY PAC and LIMO design workflows
…ompletion' into phase/162-large-dataset-storage # Conflicts: # .notes/implementation-notes.html # src/eegprep/plugins/clean_rawdata/pop_clean_rawdata.py
[Storage] Implement large-dataset storedisk semantics
Build standalone EEGPrep Sphinx manual and tutorials
…-hardening [Parity] Close final standalone evidence
|
Claude finished @suraj-ranganath's task in 7m 32s —— View job Code review
Reviewed all 12 new CLI modules and the 4 new test files. Cross-checked every referenced BlockingNone. Important
Nits
Test gaps
EEGLAB parity notes
|
|
🤖 Specification for issue #175 Problem: EEGPrep had GUI and interactive console entry points, but no stable headless CLI contract for agents or batch workflows. Agents needed machine-readable discovery, JSON results, stable error codes, safe output handling, manifests, and a version-matched usage guide instead of scraping Python APIs or GUI behavior. Approach: Add the installed Key code: Tests: Added CLI subprocess and unit tests for discovery completeness, bundled skill resources, JSON parse errors, inspect/validate, transform output safety and manifests, pipeline validate/plan/run, batch relative output handling, QC 1-based public indices, report writing, BIDS read-only validation and manifest overwrite safety, EEGLAB history mapping, nonfinite-aware dataset compare, and public entry point/package-data coverage. Verification run locally: Stacking note: This PR targets |
| EEG, *_ = clean_artifacts(EEG, **clean_kwargs) | ||
| history = "EEG = clean_artifacts(EEG" | ||
| if clean_kwargs: | ||
| history += ", " + ", ".join(f"{key}={value!r}" for key, value in clean_kwargs.items()) | ||
| history += ");" | ||
| return EEG, history |
There was a problem hiding this comment.
Important (EEGLAB parity / correctness): _apply_clean calls clean_artifacts(...) directly instead of pop_clean_rawdata(...). The transforms path (transforms.py:299) correctly routes through pop_clean_rawdata, which guards against epoched input:
if int(EEG.get("trials", 1) or 1) > 1 or np.asarray(EEG.get("data")).ndim == 3:
raise ValueError("Input data must be continuous. This data seems epoched.")(plugins/clean_rawdata/pop_clean_rawdata.py:70-71)
Pipelines impose no ordering between epoch and clean, so a config that epochs then cleans will run ASR on (nbchan, pnts, trials) data and produce garbage instead of the clear EEGLAB-style error. The hand-built history EEG = clean_artifacts(EEG, ...) is also not EEGLAB-style; everything else uses pop_* return_com history.
Suggested fix (drop the manual history string too):
| EEG, *_ = clean_artifacts(EEG, **clean_kwargs) | |
| history = "EEG = clean_artifacts(EEG" | |
| if clean_kwargs: | |
| history += ", " + ", ".join(f"{key}={value!r}" for key, value in clean_kwargs.items()) | |
| history += ");" | |
| return EEG, history | |
| EEG, history = pop_clean_rawdata(EEG, gui=False, return_com=True, **clean_kwargs) | |
| return EEG, history |
This restores the continuous-data guard and the EEGLAB pop_clean_rawdata(...) history. Requires importing pop_clean_rawdata instead of clean_artifacts.
| _add_common_arguments(parser, include_common_flags=include_common_flags) | ||
| parser.add_argument("--method", choices=("runica", "picard", "amica", "runamica15"), default="runica") | ||
| parser.add_argument("--seed", type=int, help="Random seed for backends that support one.") | ||
| parser.add_argument("--deterministic", action="store_true", default=True) |
There was a problem hiding this comment.
Important: --deterministic is declared action="store_true", default=True, so args.deterministic is always True and there is no way to turn it off. For runica without --seed this unconditionally forces options["rndreset"] = "off" (_ica_options, line 411-412), making EEGLAB's default non-deterministic random-reset behavior unreachable from the CLI. Compare --reorder/--no-reorder two lines below, which correctly provide the paired flag.
| parser.add_argument("--deterministic", action="store_true", default=True) | |
| parser.add_argument("--deterministic", dest="deterministic", action="store_true", default=True) | |
| parser.add_argument("--no-deterministic", dest="deterministic", action="store_false") |
Adds the headless
eegprepCLI for agent and batch workflows with JSON discovery, schemas, bundled skill guide, inspect/validate, transforms, pipelines, batch, QC/report, BIDS, and EEGLAB migration helpers.Stacking note: this PR is intentionally pointed at
develop, but it is stacked on #174 (feature/eeglab-full-standalone-completion) and should not be merged before #174 lands. Reviewers should expect the diff to include parent-stack changes until #174 is merged or this branch is rebased.Fixes #175