Asi neurofeedback-oracle
install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/neurofeedback-oracle" ~/.claude/skills/plurigrid-asi-neurofeedback-oracle && rm -rf "$T"
manifest:
skills/neurofeedback-oracle/SKILL.mdsource content
Neurofeedback Oracle
Formal Specification
Type
<<<<<<< HEAD NeurofeedbackOracle : Focus → Trit Focus = f32 ∈ [0.0, 1.0] -- EEG-derived focus score Trit = {-1, 0, +1} Thresholds (FIXED — from propagator.zig, not hyperparameters): f > 0.66 → +1 (high focus → Generator) f < 0.33 → -1 (low focus → Validator) otherwise → 0 (medium → Coordinator) ======= NeurofeedbackOracle : Focus -> Trit Focus = f32 in [0.0, 1.0] -- EEG-derived focus score Trit = {-1, 0, +1} Thresholds (FIXED -- from propagator.zig): f > 0.66 -> +1 (high focus) f < 0.33 -> -1 (low focus) otherwise -> 0 (medium) >>>>>>> origin/main
Preconditions
<<<<<<< HEAD
— result of EEG signal processing, NOT raw voltagefocus ∈ [0.0, 1.0]- Focus score is derived from at least one of:
- 8-channel EEG band-power ratio (beta/alpha)
- Fisher-Rao distance from baseline EEG state on the SPD manifold
- Neurofeedback session score (accumulated, not instantaneous)
- The oracle has access to a live or recorded EEG session (port :7069 or file)
Postconditions
- Returns exactly one value in
— never null, never float{-1, 0, +1} - Deterministic: same focus score → same trit (no noise, no randomness)
- Boundaries are EXCLUSIVE-EXCLUSIVE: f=0.66 → 0 (not +1); f=0.33 → 0 (not -1)
- If focus is undefined (no EEG signal): returns
— NOT 0CellValue.nothing
=======
-- result of EEG signal processing, NOT raw voltagefocus in [0.0, 1.0]- Focus score derived from at least one of:
- 8-channel EEG band-power ratio (beta/alpha)
- Fisher-Rao distance from baseline EEG state on the SPD manifold
- Neurofeedback session score (accumulated, not instantaneous)
- Oracle has access to a live or recorded EEG session (port :7069 or file)
Postconditions
- Returns exactly one value in
-- never null, never float{-1, 0, +1} - Deterministic: same focus score -> same trit
- Boundaries are EXCLUSIVE-EXCLUSIVE: f=0.66 -> 0 (not +1); f=0.33 -> 0 (not -1)
- If focus is undefined (no EEG signal): returns
-- NOT 0CellValue.nothing
origin/main
Implementation (from propagator.zig)
<<<<<<< HEAD // Requirement: focus ∈ [0.0, 1.0] (EEG-derived focus score) // Postcondition: trit ∈ {-1, 0, +1}, deterministic // Source: propagator.zig::neurofeedback_trit fn neurofeedback_trit(focus: f32) Trit { return if (focus > 0.66) .plus // high focus → Generator (+1) else if (focus < 0.33) .minus // low focus → Validator (-1) else .zero; // medium → Coordinator (0) } // Propagator function that CONSUMES focus Cell and PRODUCES trit Cell ======= fn neurofeedback_trit(focus: f32) Trit { return if (focus > 0.66) .plus else if (focus < 0.33) .minus else .zero; } >>>>>>> origin/main fn neurofeedback_gate(focus: Cell(f32), brightness: Cell(f32)) Propagator { return Propagator{ .inputs = &[_]*Cell{&focus}, .outputs = &[_]*Cell{&brightness}, .function = struct { fn run(inputs: []CellValue(f32), outputs: []CellValue(f32)) void { const f = inputs[0]; <<<<<<< HEAD // Only fire if focus is known if (f == .nothing) return; // CellValue.nothing → do nothing const trit = neurofeedback_trit(f.value); // Map trit to brightness: -1→dim, 0→medium, +1→bright ======= if (f == .nothing) return; const trit = neurofeedback_trit(f.value); >>>>>>> origin/main outputs[0] = .{ .value = switch (trit) { .minus => 0.2, .zero => 0.5, .plus => 1.0, }}; } }.run, }; }
<<<<<<< HEAD
EEG → Focus Score Pipeline
Preconditions for the pipeline
Requirement: 8-channel EEG at sampling rate ≥ 128 Hz Requirement: Channels: Fp1, Fp2, F3, F4, C3, C4, P3, P4 (standard 10-20) Requirement: Artifact rejection applied before focus computation Requirement: Window size = 1.0 second (128 samples at 128 Hz)
=======
EEG -> Focus Score Pipeline
origin/main
Stage 1: Band Power
<<<<<<< HEAD # Requirement: signal s is 128-sample window, Fs=128 Hz # Postcondition: band_power ∈ ℝ≥0 for each band ======= >>>>>>> origin/main from scipy.signal import welch import numpy as np def band_power(s: np.ndarray, Fs: float, band: tuple[float, float]) -> float: <<<<<<< HEAD """ Requirement: len(s) >= 64 (at least 0.5s at 128 Hz) Postcondition: returns power spectral density in [band[0], band[1]] Hz """ ======= """Returns power spectral density in [band[0], band[1]] Hz.""" >>>>>>> origin/main freqs, psd = welch(s, Fs=Fs, nperseg=min(len(s), 64)) idx = np.logical_and(freqs >= band[0], freqs <= band[1]) return float(np.trapz(psd[idx], freqs[idx])) def compute_focus(eeg_window: np.ndarray, Fs: float = 128.0) -> float: """ <<<<<<< HEAD Requirement: eeg_window.shape = (8, 128) — 8 channels, 1 second Postcondition: focus ∈ [0.0, 1.0] Focus = mean beta/alpha ratio across channels, sigmoid-normalized. Beta band: 13-30 Hz Alpha band: 8-12 Hz ======= eeg_window.shape = (8, 128) -- 8 channels, 1 second at 128 Hz Returns focus in [0.0, 1.0]. Focus = mean beta/alpha ratio across channels, sigmoid-normalized. >>>>>>> origin/main """ ratios = [] for ch in range(eeg_window.shape[0]): beta = band_power(eeg_window[ch], Fs, (13.0, 30.0)) alpha = band_power(eeg_window[ch], Fs, (8.0, 12.0)) if alpha > 0: ratios.append(beta / alpha) <<<<<<< HEAD if not ratios: return None # → CellValue.nothing upstream raw = np.mean(ratios) # Sigmoid normalization to [0,1]; scale=2.0 sets midpoint at ratio=1.0 ======= if not ratios: return None # -> CellValue.nothing upstream raw = np.mean(ratios) >>>>>>> origin/main return float(1.0 / (1.0 + np.exp(-2.0 * (raw - 1.0))))
Stage 2: Fisher-Rao Distance (alternative focus metric)
<<<<<<< HEAD # Requirement: geomstats installed; positive-definite covariance matrices # Postcondition: fisher_rao_focus ∈ [0.0, 1.0] # Rationale: distance from baseline SPD matrix = deviation from rest state = focus from geomstats.geometry.spd_matrices import SPDMatrices from geomstats.geometry.riemannian_metric import RiemannianMetric SPD = SPDMatrices(n=8) # 8×8 SPD manifold for 8 EEG channels def fisher_rao_focus(current_cov: np.ndarray, baseline_cov: np.ndarray) -> float: """ Requirement: current_cov, baseline_cov are 8×8 positive-definite matrices Requirement: baseline_cov computed from 30s resting-state EEG Postcondition: focus ∈ [0.0, 1.0] via sigmoid normalization of geodesic distance Fisher-Rao distance = geodesic distance on SPD manifold """ dist = SPD.metric.dist(current_cov, baseline_cov) # Normalize: dist=0 → focus=0.0 (at baseline), dist large → focus→1.0 return float(1.0 / (1.0 + np.exp(-0.5 * (dist - 2.0))))
Cell Integration (Propagator Network)
// Full propagator network: EEG → Focus → Trit → Brightness // // EEG Cell: CellValue([]f32) — 8-channel sample // Focus Cell: CellValue(f32) — processed focus score [0,1] // Trit Cell: CellValue(Trit) — -1, 0, +1 // Brightness: CellValue(f32) — display brightness [0,1] ======= from geomstats.geometry.spd_matrices import SPDMatrices SPD = SPDMatrices(n=8) # 8x8 SPD manifold for 8 EEG channels def fisher_rao_focus(current_cov: np.ndarray, baseline_cov: np.ndarray) -> float: """ current_cov, baseline_cov: 8x8 positive-definite matrices. baseline_cov computed from 30s resting-state EEG. Returns focus in [0.0, 1.0] via sigmoid normalization of geodesic distance. """ dist = SPD.metric.dist(current_cov, baseline_cov) return float(1.0 / (1.0 + np.exp(-0.5 * (dist - 2.0))))
Cell Integration (Propagator Network)
>>>>>>> origin/main const BciPropagatorNetwork = struct { eeg_cell: Cell([]f32), focus_cell: Cell(f32), trit_cell: Cell(Trit), brightness_cell: Cell(f32), <<<<<<< HEAD // Propagator 1: EEG → Focus (Python-computed, injected as Cell update) // Propagator 2: Focus → Trit (neurofeedback_trit, inline Zig) // Propagator 3: Trit → Brightness (neurofeedback_gate, inline Zig) fn inject_focus(self: *@This(), focus: ?f32) void { if (focus) |f| { // Precondition check: f ∈ [0.0, 1.0] std.debug.assert(f >= 0.0 and f <= 1.0); self.focus_cell.set(.{ .value = f }); } // If null: cell stays at .nothing (oracle returns nothing) ======= // Propagator 1: EEG -> Focus (Python-computed, injected as Cell update) // Propagator 2: Focus -> Trit (neurofeedback_trit, inline Zig) // Propagator 3: Trit -> Brightness (neurofeedback_gate, inline Zig) fn inject_focus(self: *@This(), focus: ?f32) void { if (focus) |f| { std.debug.assert(f >= 0.0 and f <= 1.0); self.focus_cell.set(.{ .value = f }); } >>>>>>> origin/main } fn read_trit(self: *@This()) CellValue(Trit) { return self.trit_cell.content; } };
<<<<<<< HEAD
Oracle Failure Modes
IF focus = null (no EEG signal / artifact rejection failed entire window): → CellValue.nothing → Do NOT propagate to downstream cells → Log: "neurofeedback oracle: no signal" IF focus < 0.0 or focus > 1.0 (normalization bug): → CellValue.contradiction { a = Trit.zero, b = Trit.undefined } → Halt propagator network → Log: "neurofeedback oracle: focus out of range [focus]" IF EEG session timeout (no data for > 5 seconds): → CellValue.nothing → Reset to baseline (trit = 0, brightness = 0.5) → Alert operator
Oracle Composition (BCI → Skill Graph)
# Neurofeedback trit feeds into GF(3) skill composition def bci_skill_selector(focus: float) -> Optional[str]: """ Precondition: focus ∈ [0.0, 1.0] Postcondition: returns skill name matching trit class, or None if oracle returns nothing trit = -1 → select a VALIDATOR skill (verification, constraint, reduction) trit = 0 → select an ERGODIC skill (routing, coordination, mediation) trit = +1 → select a GENERATOR skill (creation, composition, generation) """ trit = neurofeedback_trit(focus) skill_by_trit = { -1: ["gf3-trit-oracle", "bisimulation-oracle", "abductive-oracle"], 0: ["dynamic-sufficiency", "catlab-asi-interleave", "agent-o-rama"], +1: ["nonlinear-dynamics-observatory", "lolita", "monad-bayes-asi-interleave"], } candidates = skill_by_trit[trit] # Return first available candidate (deterministic, ordered by priority) return candidates[0] if candidates else None
=======
Oracle Failure Modes
IF focus = null (no EEG signal / artifact rejection failed): -> CellValue.nothing -> Do NOT propagate to downstream cells IF focus < 0.0 or focus > 1.0 (normalization bug): -> CellValue.contradiction { a = Trit.zero, b = Trit.undefined } -> Halt propagator network IF EEG session timeout (no data for > 5 seconds): -> CellValue.nothing -> Reset to baseline (trit = 0, brightness = 0.5)
origin/main
Ports and Infrastructure
EEG Input: port :7069 (raw 8-ch EEG stream, binary, 128 Hz) Focus Output: port :7070 (processed focus scores, JSON, 10 Hz) <<<<<<< HEAD Trit Output: port :7071 (GF(3) trit stream, JSON, 1 Hz) ======= Trit Output: port :7071 (trit stream, JSON, 1 Hz) >>>>>>> origin/main Session file: ~/.bci/sessions/YYYYMMDD_HHMMSS.eeg Baseline file: ~/.bci/baseline.npz (30s resting-state covariance)
<<<<<<< HEAD
What This Oracle Is NOT
- NOT a classifier (no training, no learned weights)
- NOT probabilistic (no P(trit | focus), no confidence interval)
- NOT adaptive (thresholds 0.33/0.66 are fixed specifications, not learned)
- NOT a continuous output (output ∈ {-1, 0, +1}, not a float)
- NOT defined on raw EEG voltage (must go through band-power or Fisher-Rao pipeline first)
Related Skills
— 8ch EEG, Fisher-Rao, phenomenal field, qualia marketbci-phenomenology
— propagator.zig substrate with neurofeedback_gatezig-syrup-propagator-interleave
— the general trit oracle this specializesgf3-trit-oracle
— corollary discharge connection (neurofeedback_gate IS a corollary discharge)reafference-corollary-discharge
— colored operad over EEG channelsbci-colored-operad
— sheaf-theoretic BCI modelsheaf-cohomology-bci
— Fisher-Rao distance on SPD manifold (Stage 2 pipeline)geomstats
— Radul-Sussman theory underlying Cell/Propagator model =======propagators
What This Oracle Is NOT
- NOT a classifier (no training, no learned weights)
- NOT probabilistic (no confidence interval)
- NOT adaptive (thresholds 0.33/0.66 are fixed specifications)
- NOT a continuous output (output in {-1, 0, +1})
- NOT defined on raw EEG voltage (must go through band-power or Fisher-Rao pipeline first)
origin/main