v6.0.0 is a BREAKING release. It collapses three separate v5.x surfaces into clean contracts: a single tier that drives every backend, a single hook manifest that both plugin and npm installs read from, and a single TTY test that decides protocol strictness. It also ships two new hooks that v5.x kept asking for (Notification, SubagentStop) and finally wires auto_capture.py into live conversation events with an automatic learning write on correction matches.

This release must be installed before NEXO Desktop v0.12.0 — Desktop consumes two new files this Brain publishes: src/resonance_tiers.json and ~/.nexo/hooks_status.json.

One Tier, One Source of Truth

v5.9.0 introduced the resonance map with four tiers (maximo / alto / medio / bajo), but the installer still asked operators for model and reasoning effort per backend, then saved them separately into schedule.json. The two sources of truth drifted — a user who picked maximo in the Desktop selector could still have a stale reasoning_effort="max" in schedule.json, and nothing enforced consistency. v5.10.1 patched the specific reasoning_effort=max case with a silent migration, but the underlying duplication was still there.

v6.0.0 removes the duplication. The installer asks one question:

¿Qué nivel de potencia quieres por defecto para tus conversaciones?
  1. máximo
  2. alto (recomendado)
  3. medio
  4. bajo

The answer writes preferences.default_resonance into brain/calibration.json. The per-backend model and effort now live in src/resonance_tiers.json, which src/resonance_map.py reads at import time via a new public load_resonance_table(). The map still distinguishes user-facing callers (nexo chat, Desktop new conversation, interactive nexo update) that honour the user's tier from system-owned callers (every cron and background script) that stay pinned at their pre-decided tier.

Legacy client_runtime_profiles.{claude_code,codex}.{model,reasoning_effort} are purged from schedule.json silently on upgrade. preferences.show_pending_at_start moves to NEXO Desktop's electron-store (Brain stops reading and writing it; Desktop ≥0.11.2 keeps the toggle in its own UI). None of these are mapped to new values — that would resurrect the reasoning_effort=max → maximo footgun we closed in v5.10.1. They are dropped, and the canonical defaults apply.

One Hook Manifest, Both Modes

Before v6.0.0 the plugin mode (hooks/hooks.json) and npm mode (bin/nexo-brain.js ALL_CORE_HOOKS) shipped different hook lists. Each release asked the maintainer to update both; they drifted several times (learnings #23 and #169 both exist because of this). v6.0.0 puts the canonical list in src/hooks/manifest.json:

{
  "version": "1.0",
  "hooks": [
    { "event": "SessionStart",     "handler": "src/hooks/session_start.py",   "critical": true  },
    { "event": "UserPromptSubmit", "handler": "src/hooks/auto_capture.py",    "critical": false },
    { "event": "PostToolUse",      "handler": "src/hooks/post_tool_use.py",   "critical": false },
    { "event": "PreCompact",       "handler": "src/hooks/pre_compact.py",     "critical": true  },
    { "event": "Stop",             "handler": "src/hooks/stop.py",            "critical": true  },
    { "event": "Notification",     "handler": "src/hooks/notification.py",    "critical": false },
    { "event": "SubagentStop",     "handler": "src/hooks/subagent_stop.py",   "critical": false }
  ]
}

Both hooks/hooks.json (plugin) and bin/nexo-brain.js registerAllCoreHooks() (npm) now build their command list from this manifest. registerAllCoreHooks() also prunes v5.x legacy shell hook commands (heartbeat-posttool.sh, protocol-guardrail.sh, inbox-hook.sh, …) from ~/.claude/settings.json while leaving user-custom hooks alone — the upgrade path, once and for all, consolidates to the manifest.

Notification and SubagentStop

Two new hooks ship:

auto_capture Goes Live

auto_capture.py has existed since v4.x, but it was not connected to any hook — a cron scanned archived session logs after the fact. v6.0.0 wires it as the UserPromptSubmit handler and also pipes tool results through it from post_tool_use.py. The classifier still produces decision / correction / explicit facts, but now:

The hook never raises. If tools_learnings is unavailable (fresh install, tests), the call degrades silently and the pipeline stays up.

Protocol Strictness Follows the TTY

v5.x gave users three knobs (env, calibration preference, aliases) to tune strict/lenient/learning. Nobody used them except Francisco, and he reported confusion every time he forgot which one he had set. v6.0.0 removes the knobs:

NEXO_PROTOCOL_STRICTNESS is gone. preferences.protocol_strictness is gone. The default/normal/off/warn/soft aliases are gone. VALID_PROTOCOL_STRICTNESS still exposes learning for internal code paths that want it, but no configuration surface touches that value. Every test and every cron inherits the right mode automatically.

Hooks Status Published for Desktop

After every registerAllCoreHooks() invocation, the installer writes ~/.nexo/hooks_status.json:

{
  "generated_at": "2026-04-17T13:30:00Z",
  "nexo_version": "6.0.0",
  "total": 7,
  "registered": 7,
  "healthy": true,
  "hooks": [
    {"event": "SessionStart",     "handler": "session_start.py",   "status": "active"},
    {"event": "UserPromptSubmit", "handler": "auto_capture.py",    "status": "active"},
    ...
  ]
}

NEXO Desktop ≥0.12.0 reads this file to render Hooks activos X/Y in the Estado del sistema tab. If any handler file is missing on disk, its row becomes status: "error" and healthy flips to false — Desktop then shows a red dot and a one-click fix button. No more silent hook breakage between releases.

Also

Tests

Seven new test modules cover the new surface: test_resonance_loader.py, test_migration_legacy_to_v6.py, test_auto_capture_correction_learning.py, test_protocol_strictness_tty.py, test_hooks_status_publish.py, test_v6_hooks_manifest_parity.py, and test_v6_fresh_install_skip.py. Full suite: 1057 passed, 1 skipped.

Full changelog →