Skip to content
NeuroDock

Proactive guardrails

NeuroDock’s chronometric and guardrail MCP servers expose tools for detecting hyperfocus, rumination, and sycophancy. Pre-0.0.23, every one of those tools required a manual call — type “check my session” or invoke an MCP tool. That’s the wrong shape: an ND user in hyperfocus is the person least likely to remember to call the break tool.

The proactive-guardrails layer flips the pattern from pull-by-user to push-by-watchdog. The same heuristics run, on the same data, but they’re triggered automatically by a background watcher and surfaced via a non-blocking banner.

Three independent watchers, three blind spots covered:

WatcherCatchesMisses
Claude Code hook (Phase 1)Hyperfocus during long Claude Code sessions, rumination across prompts, sycophancy in assistant turnsNon-Claude work
Browser-extension watchdog (Phase 2)Hyperfocus in translation activity, single-host rumination, late-night decodingNon-browser work
Standalone daemon (Phase 3)Everything else — terminal sessions, IDE work, gaming after workNone (full host coverage)

A serious install runs all three. The first two cover the common case; the daemon is opt-in for users who want host-agnostic coverage.

Terminal window
neurodock install-hooks --self-test

Wires four entries into ~/.claude/settings.json:

{
"hooks": {
"SessionStart": [{ "matcher": "", "hooks": [{ "type": "command", "command": "python \"~/.neurodock/hooks/proactive_guardrail.py\" session-start" }] }],
"PreToolUse": [{ "matcher": "", "hooks": [{ "type": "command", "command": "python \"~/.neurodock/hooks/proactive_guardrail.py\" pre-tool" }] }],
"PostToolUse": [{ "matcher": "", "hooks": [{ "type": "command", "command": "python \"~/.neurodock/hooks/proactive_guardrail.py\" post-tool" }] }],
"Stop": [{ "matcher": "", "hooks": [{ "type": "command", "command": "python \"~/.neurodock/hooks/proactive_guardrail.py\" stop" }] }]
}
}
  • SessionStart — opens a chronometric session, prints a “late night” banner if local time is in 00:00–05:59 or 22:00–23:59.
  • PreToolUse — every 5th tool call, evaluates hyperfocus (elapsed time vs hyperfocus_break_minutes) and rumination (Jaccard similarity over the last 90 min of prompts ≥ 3 matches).
  • PostToolUse — checks the assistant’s response text for opening unconditional agreement / praise without a trade-off named.
  • Stop — closes the chronometric session.
┌─ NeuroDock ──
│ NeuroDock hyperfocus check (95 min): worth taking a real break —
│ walk outside, switch context for 10 minutes.
└──

Always one line. Always dismissible. The hook never blocks the tool.

The service worker registers a setInterval (default 5 min) that reads the local IndexedDB translation history and evaluates:

  • Hyperfocus — ≥12 translations in 30 min.
  • Deep-night — local time 00:00–05:59 AND ≥1 translation since midnight.
  • Rumination on a single host — ≥8 translations on the same host in the last hour.

When a signal trips, the extension shows a chrome.notifications toast and flips the toolbar badge amber until the next translation.

Opt-out (per-browser):

await chrome.storage.local.set({ "neurodock.watchdog.enabled": false });

The Settings tab exposes the same toggle for users who don’t want to touch DevTools.

Terminal window
neurodock install-hooks --install-daemon --self-test

Wires the Python neurodock_daemon.py script (also bundled, stdlib only) at user-login autostart via:

  • WindowsHKCU\Software\Microsoft\Windows\CurrentVersion\Run registry entry
  • macOS~/Library/LaunchAgents/org.neurodock.guardrail.plist
  • Linux~/.config/systemd/user/neurodock-guardrail.service

The daemon polls every 5 min, reads the same state files the Phase 1 hook updates (~/.neurodock/state/guardrail-session.json, ~/.neurodock/state/guardrail-prompts.json), evaluates the same heuristics, and surfaces interventions via native notifications:

  • Windows toast (Windows Runtime API via PowerShell)
  • macOS osascript -e 'display notification ...'
  • Linux notify-send

Why a separate daemon when the hook exists? The hook only fires inside Claude Code. The daemon catches you working in a terminal at 02:00, doomscrolling at 02:30, or back in Claude Code at 03:00 with a stale started_at.

What you wantCommand / setting
Disable all three temporarilyexport NEURODOCK_GUARDRAILS=off (env var; hook + daemon both honor it)
Remove the hook + daemon entirelyneurodock install-hooks --uninstall
Disable extension watchdog onlychrome.storage.local.set({ "neurodock.watchdog.enabled": false })
Disable Phase 1 hook but keep daemonManually delete the 4 entries from ~/.claude/settings.json
Change hyperfocus thresholdEdit ~/.neurodock/profile.yamlchronometric.hyperfocus_break_minutes (Phase 1 hook respects it; Phase 3 daemon reads on next tick)

All under ~/.neurodock/state/:

FileOwnerContents
guardrail-session.jsonPhase 1 hook{ started_at, tool_count }
guardrail-prompts.jsonPhase 1 hookrolling 200-entry list of { at, text } for rumination
guardrail-log.jsonlPhase 1 hookaudit trail of every banner surfaced
daemon.jsonPhase 3 daemonlast-surfaced timestamp for dedup
daemon-log.jsonlPhase 3 daemonaudit trail of daemon events

The browser extension keeps its own state in IndexedDB (neurodock.history.v1) — distinct from the on-disk state.

Everything is local. No state file ever leaves the device. The Jaccard heuristic operates on prompt word-sets; full prompts are stored in guardrail-prompts.json for the rolling 200-entry window and never transmitted.

The on-disk audit trails (*-log.jsonl) are append-only and exist solely so you can prove to yourself, retroactively, why a given banner fired. Delete them at any time.

The proactive-guardrails design was filed on 2026-05-24 at 00:38 local, mid-way through a 4-hour straight-through extension-bug session during which none of NeuroDock’s existing safety surfaces auto-fired. Every one of the underlying tools worked correctly when called manually. None were called. The proposal document — PROPOSAL.md — captures the gap and the three-phase fix; this page is the shipped form.