name: operator-monitor-debug
description: Use when the operator monitoring pipeline appears broken: EventBus has no events, PatternDetector is not firing, elicitation dialog never appears, or OperatorMonitor is silent. Guides systematic diagnosis of the full pipeline.
Debugging the Operator Monitor Pipeline
Checklist
1. Is the remote runner running and reachable?
curl http://<runner-host>:8787/health
2. Is OperatorMonitor running?
OperatorMonitor auto-starts when a runner is configured (runner-map.json has
at least one entry) OR when EMERGE_OPERATOR_MONITOR=1 is set in the daemon
environment. Check which condition applies:
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/repl_admin.py" runner-status --pretty
3. Are events reaching the EventBus?
cat ~/.emerge/operator-events/<machine_id>/events.jsonl | tail -20
If the file is empty or missing: the event producer is not firing events.
- Check that the relevant producer path is active (
POST /operator-event, pipeline start() hook with event_bus.emit_event, or _write_operator_event from icc_exec)
- On macOS, verify the process has Accessibility permission (
System Preferences → Privacy → Accessibility)
- On Windows, check that the process has UIAutomation access and is not running in a low-integrity context
4. Is PatternDetector seeing the events?
Replay events manually via icc_exec:
import json
from pathlib import Path
from scripts.pattern_detector import PatternDetector
events_path = Path.home() / ".emerge/operator-events/<machine_id>/events.jsonl"
events = [json.loads(l) for l in events_path.read_text().splitlines() if l.strip()]
summaries = PatternDetector().ingest(events[-50:])
print(f"Summaries: {summaries}")
If summaries is empty but events exist: thresholds not met yet.
- Frequency detector fires at ≥3 same-type events in a 20-minute window
- Check that
session_role is "operator", not "monitor_sub" — monitor_sub events are filtered
5. Is OperatorMonitor polling?
Set EMERGE_MONITOR_POLL_S=5 to ensure polling is active.
Check EMERGE_MONITOR_MACHINES matches the profile names configured in the runner map.
6. Is the pattern observation reaching CC?
Pattern observations are delivered via watch_emerge.py --runner-profile <profile> (Monitor
tool, persistent). When a pattern fires, DaemonHTTPServer._on_runner_event writes a
pattern_observed entry directly to events-{profile}.jsonl. The Monitor script tails
this file and prints formatted observations to stdout; CC streams stdout into the conversation.
Check:
- Is
watch_emerge.py --runner-profile <profile> running as a persistent Monitor?
(launched by /emerge:cockpit step 4 via watch_emerge.py --runner-profile)
- Does
~/.emerge/state/events/events-{profile}.jsonl contain recent pattern_observed entries?
grep '"type": "pattern_observed"' ~/.emerge/state/events/events-<profile>.jsonl | tail -5
- If entries exist but CC didn't see them: the Monitor may have stopped — restart it.
7. Common fixes
| Symptom | Fix |
|---|
| EventBus empty | Verify event producer path (/operator-event, pipeline start(), or icc_exec) and OS accessibility permissions |
| PatternDetector never fires | Lower FREQ_THRESHOLD or check event session_role field |
| Elicitation never appears | Verify daemon has elicitation capability in MCP handshake; check thread is non-main |
| Pattern observation not delivered | Verify watch_emerge.py --runner-profile <p> Monitor is running; check events-{profile}.jsonl for pattern_observed entries |
| OperatorMonitor not starting | Confirm runner is configured (runner-status --pretty) OR EMERGE_OPERATOR_MONITOR=1 in daemon env |