Proactive Hooks are a background monitoring system that automatically triggers actions when the user's current EEG brain-state matches keywords/labels they've configured, subject to a scenario filter (cognitive, emotional, physical, or any).
There are three main components:
Each hook has:
name— identifierenabled— on/off togglekeywords— list of text keywords (e.g.["focus", "deep work", "flow"])scenario— state filter:any,cognitive,emotional, orphysicalcommand/text— payload dispatched when the hook firesdistance_threshold— max cosine distance for a match (e.g.0.14)recent_limit— how many reference EEG embeddings to keep (10–20)
The matching pipeline runs inside the EEG embed-worker thread:
-
Cache Refresh (
maybe_refresh, every 20s):- For each enabled hook, takes the configured keywords and embeds them with a text embedding model (fastembed).
- Fuzzy-expands keywords against recent labels (last 180) — if a label fuzzy-matches a keyword, it's added as an additional query.
- Searches the label index (text-embedding vector search) to find the closest labeled EEG sessions.
- For each neighbor, loads the mean EEG embedding for that label's time window → builds a set of
HookReferencevectors (up torecent_limit).
-
Fire Check (
maybe_fire, on every new EEG embedding):- Scenario gate: checks if current
EpochMetricsmatch the scenario. E.g.:cognitive→cognitive_load ≥ 55orengagement ≥ 60emotional→stress_index ≥ 55ormood ≤ 45orrelaxation ≤ 35physical→drowsiness ≥ 55orheadache_index ≥ 45or elevated/low HR
- Computes cosine distance between the live EEG embedding and each cached reference.
- If the best (smallest) distance ≤
distance_thresholdand ≥10 seconds since last fire:- Fires the hook: broadcasts a
"hook"event via WebSocket, shows a toast notification, updates runtime state, and writes to the audit log.
- Fires the hook: broadcasts a
- Scenario gate: checks if current
-
Cooldown: minimum 10 seconds between fires of the same hook.
Every hook fire is persisted to ~/.skill/hooks.sqlite with full JSON snapshots of the rule, trigger context (label, distance), and dispatched payload — so the history remains meaningful even after hook config changes.
| column | type | notes |
|---|---|---|
id |
INTEGER | PRIMARY KEY AUTOINCREMENT |
triggered_at_utc |
INTEGER | YYYYMMDDHHmmss UTC |
hook_json |
TEXT | Full copy of HookRule at trigger time |
trigger_json |
TEXT | HookLastTrigger + EEG distance details |
payload_json |
TEXT | What was dispatched (command / WS payload) |
The settings UI provides:
- CRUD for hook rules with keyword management (with autocomplete suggestions via
suggest_hook_keywords— fuzzy + semantic) - Threshold suggestion (
suggest_hook_distances) — analyzes EEG distance percentiles and recommends a threshold - Live status — polls
get_hook_statusesevery 5s showing last trigger time, matched label, and distance - Fire history — paginated audit log viewer
- Quick examples — pre-built templates for cognitive/emotional/physical scenarios
User keywords → text-embed → vector search labels → get EEG refs
↓
Live EEG epoch → embed → cosine_distance(live, refs) → below threshold?
↓
scenario gate (EEG metrics match?) → fire!
↓
WS broadcast + toast + audit log + runtime state