Every feature, fix, and improvement — from the beginning, with the same visual clarity as the rest of the site.
[features].hooks.
(file_count, size_total, max_mtime) signature. MCP startup and per-tool-call restart checks skip the 263-file rehash when disk hasn't changed. ~11× speedup warm path; ~10-20s/day saved across daily MCP startups. Cache miss self-repairs.
mcp-restart-required.json so doc-only / blog-only / changelog-only releases stop forcing connected MCP clients (Claude Code, Codex, Claude Desktop) to restart. Conservative fallback (#186) preserved; explicit force_restart opt-in for cases the fingerprint can't detect.
README.md that still documented the proxy override path as a current feature. The 7.10.0 code revert was complete; the README cleanup landed here.
llm_endpoint.json, auth_provider.json, nexo-max/high/medium/low/mini aliases, Idempotency-Key). Brain now hits api.anthropic.com directly using the user's own Claude Code OAuth.
_decode_header) plus PreToolUse Guardian hook hardened with stderr + exit 2 belt-and-suspenders so terminal Claude cannot ignore a hard block.
usedforsecurity=False); first npm release that carries the 7.9.32 email-recovery checkpoints.
stop_sequences in call_model_raw rejected by Anthropic 400; default is now None and whitespace-only caller values are rejected locally.
import sys in src/agent_runner.py that blocked the 7.9.29 publish in CI; first npm release that carries the 7.9.29 override-path hardening.
Authorization: Bearer instead of X-Api-Key, call-time config dir, caller-controllable Idempotency-Key, strict bearer source so a real ANTHROPIC_API_KEY never leaks to a custom proxy.
~/.nexo/config/ redirect Brain Anthropic SDK calls and CLI children to a proxy, with Idempotency-Key for retry dedup. Brain libre standalone unaffected.
initialize handshake on the legacy task.owner backfill (now runs --rules-only).
before_tool, on_event, conditional (previously only Desktop did). after_tool is per-instance instead of once-per-session. Map v2.2 tightens learning_add grace 3→0 and task_open threshold 10→4 must. guardian_default v1.4.0 hardens R15/R17/R22/R_CATALOG and raises R34 from shadow to soft. 6 new contract parity tests. Companion: NEXO Desktop v0.26.0.
nexo_lifecycle_event promoted to canonical authority of session-end: Brain owns prompt + sequence + timing, Desktop v0.25.0 executes the plan inline. New 2-call contract (event + complete_canonical), deterministic canonical_plan_id, session_diary dedupe, seven delivery_status values. Migration m52. MCP tools 262 → 263.
nexo_lifecycle_event is a ledger + reconciliation authority, NOT the canonical executor of diary+stop. Partner Desktop v0.24.1 wires switch/window-close/app-exit through the same durable service with NDJSON telemetry + exponential backoff reconciler.
nexo update. F0.6 hardening: nexo rollback f06, layout contract, doctor checks, Nora migration workflow. Adaptive weights empirical promotion. B10 path constants lazy. Schedule audit log. Pre-release discipline pack.
checkpoint_policy module; and verify_release_readiness.py smoke-artifact contract pass + core prompt polish.
guard_check-required gate, inline guard ack, Guardian Health briefing), Block D hardcode cleanup, Block E product guards.
email-monitor now carries the calibrated operator language through its prompt contract and localizes direct needs_interactive escalation emails, so Spanish operators stop receiving fallback English monitor mail.
synthesis template/docs match the live 06:00 manifest again.
~/.nexo/core as a mutable repo, and F0.6 compatibility shims stop breaking update replay and rollback.
core code root, layout healing after update, Guardian runtime surfaces for Desktop, productised core automations, and local classifier auto-install.
core, personal, and runtime, with transition-aware helpers and auto-migration for existing operators.
About NEXO Desktop. NEXO Desktop is a separate closed-source companion client distributed at nexo-desktop.com. When a changelog entry mentions NEXO Desktop it refers to a coordinated client release that consumes the Brain CLI/MCP contract. Desktop source does not live in this repo; the Brain (AGPL-3.0) remains fully usable on its own from terminal, Codex, Claude Code, or any MCP client.
Brain now pauses local-index, email, followup, watchdog, catchup and MCP DB writers before restoring `nexo.db`, then Doctor can repair the zero-byte or locked Local Memory database state from a validated backup.
Local Context now keeps initial indexing separate from live change tracking, persists the current indexing start time, returns compact bounded evidence for agents and installs the Windows host scheduler needed to keep WSL indexing alive after reboot.
Local Context now starts from real system volume roots plus mounted/removable/network volumes, keeps system/cache/app/product artifacts out of evidence, and injects relevant local excerpts automatically into heartbeat, task-open and pre-action context.
Local Context manual refreshes now reconcile automatic roots every time, so Desktop's check-now path picks up mounted disks and upgraded roots immediately instead of waiting for the next resident service cycle.
Local Context upgrades automatic roots beyond shallow depth, detects Linux/WSL systemd timer failures and falls back to managed crontab, passes Windows AppData email roots into WSL, blocks Google API keys before HTML cleaning, and keeps Outlook Mac proprietary message files inventory-only.
Local Context recognises Windows Mail package roots and Outlook Mac profile roots as bounded local-email sources instead of rejecting them as generic AppData or Group Containers.
Local Context email-root bootstrap is deterministic across CI, WSL and migrated profiles while preserving macOS Mail.app, Windows Outlook, Thunderbird and NEXO email coverage.
Local Context now ranks entity matches at chunk level, keeps older entity-matched assets eligible outside the base recent-chunk window, automatically adds safe local email roots for macOS, Windows and Linux, extracts `.eml`, `.emlx`, `.msg` and NEXO email DB continuity, and exposes local graph relations in pre-action context.
Local Context now blocks private dotfiles, hidden profile folders, hidden project folders and secret-bearing content before chunks, embeddings, entities, relations or agent context are created. Existing residue from older builds is repaired by local index hygiene, doctor fix and the resident service cycle.
Local Context now requeues retryable failed jobs, recovers expired running leases, reports real macOS LaunchAgent and Windows Scheduled Task results, records scan errors as retryable problems, bootstraps default roots for direct MCP/CLI runs, and preserves Windows drive roots such as C:\.
Local Context service cycles now recover from orphaned lock files and mixed-version run_once() parameter drift. If a background cycle fails, status diagnostics expose the retryable service problem until a later cycle succeeds, keeping the Desktop Local Memory view and support logs aligned with the real indexer state.
Local Context now reconciles known files and directories on every service cycle before the normal scan queue runs. Created, modified, deleted and newly excluded files are reflected automatically between full scans; changed folders are scanned in bounded batches, offline roots are not mass-deleted, and matched context queries now return graph relations alongside assets, chunks and entities.
Bundle-managed installations (NEXO Desktop brain-bundle/) can now pin Brain to the host application release cycle via the NEXO_BRAIN_AUTO_UPDATE=false environment variable. When set, startup_preflight skips the npm auto-update check entirely. Additionally, when RestartRequiredMiddleware detects installed_version != process_version, after delivering the existing mcp_restart_required response the server now auto-exits with code 75 (EX_TEMPFAIL) ~500 ms later so MCP clients respawn the server with the new code instead of leaving stale server.py processes alive.
Packaged Brain runtimes now copy the local_context package during install and update, fixing the zero-file Desktop Local Memory state caused by ModuleNotFoundError. The local-index service also rechecks automatic roots on every cycle so newly mounted volumes are indexed without manual setup unless the user excludes them.
Brain now ships the local-only memory layer that Desktop and agents can use before answering or acting: checkpointed file scanning, lightweight extraction, graph relations, deterministic local embeddings, diagnostics, service metadata for macOS and Windows, and nexo local-context plus MCP controls. The layer is wired into pre-action context so evidence from indexed local files can become part of the agent's working context without external APIs.
Standalone nexo chat now surfaces the Full Disk Access requirement when macOS has blocked a background privacy check. Brain also performs a live macOS access probe before keeping the permission marker active, so prompts disappear once the user has actually granted access.
tcc-approve now turns launchd privacy denials against the user TCC database into a guided Full Disk Access state. The helper writes runtime/state/full-disk-access-required.json, marks schedule config as later, keeps approval markers unset, and lets Desktop prompt the user to enable NEXO Desktop plus the helper executable instead of reporting an unexplained cron failure.
tcc-approve now captures macOS TCC sqlite3 failures per service, keeps version markers unset until approvals really succeed, and emits wrapper-visible status text. catchup still prefers the cron wrapper, but legacy direct fallback executions now insert and close cron_runs rows instead of only updating catch-up state.
nexo --version --json now returns machine-readable update status: installed, latest, hasUpdate, unknown and latestSource. Desktop can populate the Updates panel without scraping slow help output. The human nexo --version output keeps the existing nexo vX first line and adds a compact latest/installed status line for older Desktop fallbacks.
Automation runners now distinguish full NEXO agents from strict technical children. Real background agents keep task/evidence/diary/learning/followup discipline; strict JSON children stay clean. Guardian metrics count the real injection event, and runtime doctor now warns when core cron activity lacks matching caller-attributed automation rows.
The local model manifest now marks qwen3-0.6b-q4-local-presence as optional for standalone Brain. LocalModelSpec carries a required bit, warmup_targets() propagates it into strict warmup, and install/update continues when that Desktop-only GGUF is not bundled or already cached locally. Required Brain models — classifier, embeddings, and reranker — still fail the release path if warmup breaks.
email-monitor now requires a guard check before creating or editing its suffixed /tmp/nexo-reply-UID.txt, /tmp/nexo-quote-UID.txt, and /tmp/nexo-thread-UID.txt draft buffers. morning-agent now installs SIGTERM/SIGINT handlers, marks active briefing claims failed on interruption, retries stale in_progress claims with previous-run metadata, keeps the CLI timeout under the supervisor ceiling, and keeps the recent sent-block idempotent. Codex managed config now writes [features].hooks = true and removes the legacy codex_hooks key.
Claude CLI 2.1+ with bare_mode=True + output_format="json" + a prompt requesting raw JSON drops the classic {"result": "...", "usage": {...}} wrapper and returns the agent's JSON answer directly. Pre-7.17.1 _extract_claude_telemetry only knew the wrapper shape: payload.get("result", "") returned "" and the empty final_stdout made every downstream JSON parser raise. The morning-agent cron was failing silently every tick — 178 fails in morning-agent.log on 2026-05-10 vs 75 successful telemetry rows in automation_runs with intact subject+body payloads. Now both shapes are normalised: classic-wrapper callers keep their behaviour; direct-JSON callers receive the full payload as final_stdout (usage/cost telemetry is unavailable in this mode, so we surface zeros rather than invent figures).
_run_headless_runner_guard never returns blocked=True. It still surfaces learnings, schemas, and blocking-rule text to the agent up front for context (and still writes to guard_checks for observability), but the run always proceeds. The authoritative protection layer is the PreToolUse hook (hook_guardrails._collect_runtime_core_write_blocks and the file-conditioned learning blocks alongside it), which fires only when the agent actually attempts a Write/Edit, with severity error. That layer has full intent context; the pre-emptive layer was relying on regex over prompt text, which cannot tell a write from a read or a passing mention. v7.16.2 closed the subprocess-invocation case, v7.16.3 closed the runtime-core duplication, and v7.16.4 (rolled into this release) closed the directory-path crash. v7.17.0 closes the entire family. Errors from handle_guard_check are also non-blocking now: even an unhandled exception logs as advisory and lets the run start.
handle_guard_check now accepts enforce_runtime_core_block="false". The headless runner pre-emptive guard passes that flag because actual writes on ~/.nexo/core/ paths are already blocked at the PreToolUse layer (hook_guardrails._collect_runtime_core_write_blocks, severity error). The previous duplication caused the runner to abort sessions whenever a prompt merely mentioned a core path, even without an interpreter prefix; v7.16.2 only addressed the specific subprocess pattern. Default callers (direct nexo_guard_check from agents) keep the historical behaviour and still surface the runtime-core blocking rule.
The pre-emptive runner guard scanned the prompt for absolute paths and treated every match as an edit target. The email-monitor template instructs the agent with python3 /Users/.../core/scripts/nexo-send-reply.py --to ..., so the path of the reply tool itself entered the guard's file list, the runtime-core rule fired, and the session aborted with exit 2 before the agent could draft a reply. Brain now recognises subprocess invocations: paths that follow a known interpreter (python, python3, node, bash, sh, npx, pnpm, yarn, uv, pipx, env, pwsh, powershell) are excluded from the guard list. Paths in genuine edit instructions and other CLI args (body files, quote files) still go through the guard.
Brain now captures evidence-backed operational memory from tool writes and task closeouts, derives durable observations, backfills existing installs from prior protocol/change/diary context, exposes health and maintenance tools, and refuses memory answers that do not carry evidence refs.
Brain now treats normal Codex startup context reads of NEXO calibration and project atlas files as healthy bootstrap activity instead of conditioned-file drift. Real post-bootstrap file work remains audited.
Brain now drains up to 50 repeated self-audit clusters per pass, bounds hook history with numeric retention and update-time cleanup, ignores normal Codex pre-startup reads of calibration and project atlas files, routes email-monitor effort by message complexity, and uses an atomic lock per local date and recipient so scheduler and daemon paths cannot send duplicate morning briefings.
Brain now records sent-email continuity across direct and daemon send paths, moves cognitive recall to a pinned multilingual embedding model with automatic re-embedding, forces tagged learnings into context with floor strength, adds hard email loop guards, exposes learning creation dates, cools down passive protocol reinjections after task close, runs guard checks before mutable headless runners, and writes AUTO-N burst postmortems.
Brain closes the install and operational reliability loop after the fresh-machine audits: Desktop-managed update/repair paths recover stale venvs, bundled wheels are platform-gated, Windows WSL preserves Desktop bootstrap flags, startup warns on conflicting legacy memory, legacy MEMORY writes are blocked unless explicitly overridden, external actions require real-world verification before closure, and stale followups are triaged instead of accumulating silently.
Brain now moves aside an existing managed .venv when it was created with unsupported Python <3.10, then recreates it with the supported interpreter prepared by Desktop. This closes the half-failed install path where a previous Python 3.9 venv could survive and make later installs fail at fastmcp dependency resolution.
Brain now rejects Python <3.10 before dependency installation, honors the Python interpreter prepared by Desktop through NEXO_BOOTSTRAP_PYTHON / NEXO_PYTHON, and fails clearly instead of surfacing fastmcp resolution noise from Apple Python 3.9 during fresh Mac installs.
Brain now exposes nexo_card_catalog, nexo_card_get, and nexo_card_match so agents can match non-trivial user work to official NEXO protocol cards fetched from the authenticated backend at runtime. The protocol corpus remains server-side and is not embedded in npm, the open-source repo, or the Desktop package.
Codex hook sync now renders the managed PreToolUse guard with native Windows cmd.exe syntax for Bash, shell_command, and exec_command while preserving the existing POSIX command on macOS/Linux. This closes the native Windows hook parity risk without changing Desktop installation or the Brain runtime contract.
Correction-driven learnings now persist as durable requirements and block task/session close until a real learning is added; doctor --fix explicitly repairs orphan personal schedule metadata; protected com.nexo.*.plist unload/remove flows warn with the launchctl + source-marker + dry-run removal path; Codex sync installs a managed PreToolUse guard for shell/exec_command calls; and installation_live.codex_protocol_compliance fails if that live hook is missing or if Codex sessions drift beyond the allowed threshold.
Doctor repairs orphan personal script metadata and skips historical runtime snapshots; nexo update prunes runtime snapshots older than two back; protocol compliance auto-opens edit tasks, records write-tool change visibility, and auto-closes stale tasks as partial; headless automation avoids the old six-hour hang path; Guardian false positives are tightened; and Codex bootstrap/config/automation parity is release-gated.
Packaged updates now run safe maintenance even when the bundled Brain semver is unchanged, Deep Sleep clears process locks on shutdown, sent replies persist durable continuity, and personal script reconcile reports schedule-marker drift.
Dashboard followup execution now respects the configured terminal client and opens the right native terminal path on macOS, Windows via WSL, and Linux instead of returning a macOS-only launcher failure.
This patch removes the last silent routing bypasses that were still letting legacy automation surfaces drift away from the resonance engine. src/agent_runner.py no longer lets task_profile prefill backend/model/reasoning effort ahead of resonance resolution, while src/client_preferences.py now normalizes persisted automation_task_profiles back to empty routing fields so schedule.json cannot keep acting as a hidden second source of truth. In parallel, src/scripts/nexo-email-monitor.py stops carrying its private automation_task_profile path and now resolves exactly like Deep Sleep and morning-agent: caller -> backend -> mapped model/effort. src/scripts/nexo_personal_automation.py also stops injecting resolve_user_model() into short text runs, so personal scripts only override model when the operator explicitly asks them to. Finally, src/auto_update.py scrubs the retired email routing key from legacy runtime config during update. Result: updated installs, email handling, and personal automations all converge on the same caller/tier-driven motor path instead of preserving stale model overrides in configs or helpers.
This patch closes two reliability gaps that were still creating operator friction after 7.12.0. First, src/hook_guardrails.py no longer treats SSH remote-write detection as only the quoted-inline form. The same G3 gate now catches stdin, heredoc, and pipe-to-SSH variants such as ssh host < script.sh, ssh -T host <<EOF, and printf ... | ssh host bash, while recent positive Cortex evaluations in the same session and open task authorize the next matching retry for a short TTL instead of forcing process-wide shadow overrides. Second, src/scripts/nexo_personal_automation.py now routes short text-only cron work through bare one-shot runs: no bootstrap, no default tool exposure, 180-second timeout, inferred personal/<script> caller ids, and per-caller overlap locks. Result: remote deploy/recovery flows stop dead-ending right after nexo_cortex_decide, and text-only cron jobs stop sitting around for hours or stacking overlapping subprocesses.
This release closes two support/reliability gaps that were still split across different layers. First, src/support_snapshot.py adds a generic local diagnostics bundle exposed as nexo support-snapshot. The command emits one JSON payload with version/platform metadata, runtime path presence, health-check output, and recent event/operation tails, with optional doctor output when --include-doctor is requested. That gives support and debugging work a stable runtime snapshot without crossing the open-source/commercial boundary. Second, the live Protocol Enforcer path now matches the stricter silent-reminder contract that template-level prompts already had. tool-enforcement-map.json upgrades startup / smart-startup / heartbeat / reminders / diary / stop / task-close / compaction prompts to explicit whole-turn silence, and src/enforcement_engine.py defensively upgrades any legacy one-line Do not produce visible text. reminder before enqueueing it. Result: background reminders stop leaking orphan assistant continuations into Desktop when there is no fresh operator message.
This patch closes the reminder-contract gap that could still leak visible prose into Desktop conversations after a silent tool call. The fix is deliberately prompt-level and shared: templates/core-prompts/server-mcp-instructions.md now states that when a reminder says not to produce visible text, the silence applies to the entire reminder turn; templates/CLAUDE.md.template mirrors that bootstrap rule; templates/core-prompts/post-tool-inbox-reminder.md now asks for heartbeat-only output with no prose before or after it; and templates/core-prompts/lifecycle-diary-stop.md now requires the same full-turn silence for close/app-exit diary+stop flows, including empty visible output when there is no fresh operator message. src/lifecycle_prompts.py bumps canonical lifecycle plans to PLAN_VERSION = 6 so Desktop receives the stricter contract under a new deterministic plan version. Result: consecutive silent reminders stop surfacing stray text such as En pausa esperando tu siguiente paso... in Desktop, while canonical close/app-exit plans keep the same diary/stop intent with a clearer silence rule. Validation: 48 targeted tests across prompt, enforcement, and lifecycle surfaces, plus release-readiness.
After the 7.11.6 tester-bug pass, the remaining debt was no longer broken runtime behavior but diagnosis drift. src/doctor/providers/runtime.py now skips evolution freshness when the product contract disables it, treats historical conditioned-file drift as healthy once open conditioned debt is zero, excludes cancelled tasks from change_log coverage, ignores successful headless zero-usage zero-cost runs when computing automation telemetry coverage, and keeps recent in-flight cron rows healthy instead of showing them as stale. In parallel, src/scripts/runner-health-check.py now treats supervisor SIGTERM 143 interruptions as benign reloads instead of failures, and it supports both sqlite3.Row and tuple-shaped query results so the live script no longer breaks on the runtime DB path. The net result is simple: the runtime tier of nexo doctor returns to healthy on the live install after the backlog cleanup, instead of staying yellow or red on false positives. Validation: 104 targeted tests across doctor and runner health, plus source-runtime doctor smoke returning overall_status: healthy.
This patch ships the subset of a tester report that was still reproducible on the current 7.11.5 code and runtime. First, src/hook_guardrails.py now rejects more slash fragments before they turn into protocol debt: regex and shell artifacts containing |, =, or ;; date-like tokens such as /04/2026; and non-extension multi-segment slash tokens that do not exist on disk. That closes the still-live G4 noise path where quoted fragments and date substrings were reaching g4_guard_check_required and strict_protocol_write_without_task as if they were real targets. Second, strict missing-task writes still block, but when the same session has a heartbeat in the last 5 minutes the stored debt severity is now warn instead of error, so dashboards can distinguish active-session protocol drift from fully untracked edits. Third, src/scripts/deep-sleep/extract.py now validates the live extraction contract itself — session_id, findings, and structured protocol_summary — before declaring success. Structurally degraded JSON is marked as deterministic json_schema failure and persisted to debug-extract-*-json_schema.txt instead of silently feeding partial payloads into synthesis. Validation: 50 targeted tests across hook guardrails and Deep Sleep extraction.
Live runtime validation after the 7.11.4 packaged-runtime parity repair exposed one more contract bug. nexo doctor --plane installation_live correctly treated a standalone com.nexo.dashboard.plist LaunchAgent as drift when Desktop managed the product surface, but cron sync and the watchdog still expected dashboard as a core keepalive service because src/product_mode.py only blocked evolution. Repairing the drift made the watchdog fail; refreshing the runtime reinstalled the dashboard to satisfy the watchdog and reintroduced the drift. v7.11.5 closes that contradiction at the source: DESKTOP_DISABLED_FEATURES now includes dashboard, and is_cron_blocked() checks membership in that set instead of a one-off evolution branch. On Desktop-managed installs the standalone dashboard is now blocked, not installed, and not monitored, so installation_live, cron sync, and watchdog agree on the same product contract. Validation: 125 targeted tests across product-mode, cron sync, and doctor, plus the full pre-release wrapper stayed green (2321 passed, 2 skipped, 1 xfailed, 4 xpassed).
Source checkouts and packaged installs had drifted into two different contracts. Root JSON runtime files such as local_model_manifest.json could exist in the repo but never arrive in ~/.nexo/core, install/update paths still depended on a stale JS allowlist instead of src/crons/manifest.json, runner-health-check wrote a report that no product surface consumed, and the watchdog only healed some failures after a stale-age window even when the cron had already exited non-zero. v7.11.4 closes the whole loop. Packaged runtimes now sync root *_manifest.json, *_defaults.json, and *_tiers.json contracts through both bin/nexo-brain.js and src/auto_update.py; fresh install, same-version refresh, and versioned migration/update now call manifest-driven cron sync first via syncCoreProcessesFromManifest(...); runner-health-check is registered in the cron manifest, its dead followup-activity query is fixed, doctor/runtime health reads the report, and dashboard exposes both runner-health-report.json and morning-briefing-latest.md; nexo-watchdog.sh now treats run_once_on_wake as a catchup-style recovery policy and retries failed crons immediately instead of waiting for stale windows, while also scoping stuck-wrapper PID matches to the current runtime wrapper path so one install cannot mistake another install's wrapper that happens to share the same cron_id. Validation: 117 targeted tests across cron recovery, packaged runtime/update, dashboard, local models, and runtime update contracts stayed green.
Root-cause fix for the mcp_restart_required lockup that v7.11.2 only masked at the enforcer layer. _FINGERPRINT_EXCLUDE_DIRS in src/runtime_versioning.py was missing "versions", so compute_mcp_runtime_fingerprint() walked into core/versions/<old>/**.py whenever it was called against the live runtime root. installed_runtime_fingerprint() (which resolves through active_runtime_root() → core/versions/<active>/) returned a clean per-snapshot hash, while prime_process_fingerprint() (which starts from Path(__file__).resolve().parent → live core/) accumulated every retained snapshot under core/versions/. The two never matched after the second-ever nexo update on a host. Every update wrote mcp-restart-required.json and the marker could never be cleared by _ack_current_client_if_restarted() because the installed_fp != process_fp test always returned True. Every non-allowlisted MCP tool (nexo_reminders, nexo_smart_startup, nexo_guard_check, nexo_task_open, …) returned {"error": "mcp_restart_required", "reason": "fingerprint_mismatch"} indefinitely, even after the operator restarted the client (the new client connected to the same server with the same cached PROCESS_FINGERPRINT). v7.11.2 silenced the enforcer-side noise but the marker itself stayed stuck, so user-driven calls kept failing across sessions. Adding "versions" to _FINGERPRINT_EXCLUDE_DIRS restores parity: both fingerprint computations now hash the same set of files regardless of which entry path the caller starts from. 1 new regression test in tests/test_runtime_fingerprint.py (test_fingerprint_ignores_versions_subtree) seeds three snapshot directories under versions/ and asserts the fingerprint does not shift. The two existing exclude-dir tests now also cover "versions". All 21 tests in tests/test_runtime_fingerprint.py stay green.
Two reliability fixes in the same family — components ignoring signals they should respect. The Guardian/Enforcer (HeadlessEnforcer in src/enforcement_engine.py) periodically injects <system-reminder> blocks asking the agent to call nexo_* tools (heartbeat, session_diary_write, smart_startup, guard_check, etc). When the MCP server has the ~/.nexo/runtime/operations/mcp-restart-required.json marker on disk (written by plugins/update.py after a nexo update that actually changes runtime .py bytes — cf. v7.11.0 fingerprint gating), every one of those reminders triggered a tool call that immediately failed with mcp_restart_required. The agent burned cycles on guaranteed no-ops until the operator restarted the client. v7.11.2 adds a gate at the top of _enqueue(): if the prompt mentions nexo_ and the marker file exists, skip + log SKIP: ... mcp_restart_required marker present. Reminders that don't reference nexo_* (R23 deploy guards, R25 nora/maria read-only, etc.) still fire — they don't depend on the MCP being live. New helpers: _mcp_restart_marker_path() (resolves canonical F0.6 location with pre-F0.6 fallback) and _mcp_restart_pending() (cached per-instance with 30s TTL so we don't stat the marker on every _enqueue call). Conservative: any path/IO error returns False so the gate never blocks legitimate enforcement. 6 new tests in tests/test_enforcer_restart_required_gate.py; 52 existing enforcer tests stay green.
v5.8.1 taught the watchdog to leave running jobs alone — every cron now opens a row in cron_runs at start (started_at set, ended_at NULL) and the watchdog reads that row to tell currently running from missed/stuck. That fix closed the loop where the watchdog kept kickstart -k'ing deep-sleep mid-flight (2026-04-14..17). The same restraint became the next failure mode: when a wrapper child genuinely hangs — e.g. headless claude --bare blocked on an MCP that flagged mcp_restart_required after a brain update — the row stays open forever, the next tick sees Another instance running. Skipping, and the watchdog only logged WARN. morning-agent, followup-runner and orchestrator-v2 went silent for days (2026-04-24..27) because a single zombi wrapper held the slot indefinitely. v7.11.2 adds run_stuck_reaper() at the top of every watchdog tick: it reads every cron_runs row with ended_at IS NULL and compares its age to stuck_after_seconds (per-cron from src/crons/manifest.json, fallback STUCK_DEFAULT_SECONDS=43200 = 12h global). Live wrapper → SIGTERM to the wrapper PID via pgrep -f "nexo-cron-wrapper.sh CRON_ID "; the wrapper's existing trap forwards to the child and runs finalize_row, closing the row at exit_code=143. After 10s grace, any survivor (wrapper + descendants) gets SIGKILL via pkill -KILL -P. Orphan zombi row (wrapper PID gone, row still NULL) → cleaned in-band: ended_at=now, exit_code=137, summary='stuck row reaped by watchdog: wrapper PID gone'. cron_id='watchdog' is hard-coded into STUCK_REAPER_SKIP — never reap ourselves mid-tick. Per-cron overrides for known long-runners protect the v5.8.1 case: deep-sleep: 28800 (8h), sleep: 14400 (4h), evolution: 14400 (4h, weekly heavy run). Short-runners get tighter bounds: morning-agent: 1800, followup-runner: 1800, email-monitor: 600. New observability counter TOTAL_REAPED in three places: watchdog-status.json (summary.reaped), human report header (REAPED:), final log line (REAPED=N). 6 new tests in tests/test_watchdog_stuck_reaper.py: fresh in-flight row left alone (v5.8.1 regression guard), per-cron threshold respected (deep-sleep 8h not reaped at 4h), orphan zombi row cleaned in-band with exit_code=137, real wrapper killed via SIGTERM with the trap closing the row at exit_code=143, cron_id='watchdog' never reaped, default 12h threshold applied to crons not in manifest. The 3 existing watchdog tests stay green.
v7.11.0 introduced the runtime fingerprint that gates mcp-restart-required.json by hashing every .py file under src/ the live MCP can import. The hash is checked at server startup via prime_process_fingerprint() and on every tool call via installed_runtime_fingerprint() through resolve_restart_required(). On a 263-file tree that costs ~40ms cold and is paid by every MCP startup — Claude Code, Codex, headless followup-runner, deep-sleep, every cron job. Daily cumulative: 10-20s of pure rehashing of bytes that didn't change. v7.11.1 caches the fingerprint at ~/.nexo/runtime/operations/fingerprint-cache.json with a cheap signature key — (src_dir, file_count, size_total, max_mtime) over the same set of .py files the v7.11.0 fingerprint covers. When the on-disk signature still matches the cached one, the cached digest is returned without re-reading any byte. Local benchmark on the live src/: cold ~39.9ms → warm ~3.7ms (≈11× speedup). Cache miss is always safe — corrupt JSON, signature drift, missing file all fall through to the full hash and rewrite the cache atomically. New keyword-only parameter compute_mcp_runtime_fingerprint(src_dir, *, use_cache=False) — default stays False so plugins/update.py always sees ground truth around git pull / npm update; the hot callers (installed_runtime_fingerprint, prime_process_fingerprint) opt in. Behavior of the restart gate itself is identical to v7.11.0. 6 new tests in tests/test_runtime_fingerprint.py: cache hit skips all .py reads (verified by spying on Path.read_bytes), cache miss when a .py file changes, cache miss when src_dir changes, corrupt cache falls back and self-repairs, default use_cache=False keeps update.py on the ground-truth path, prime_process_fingerprint warms the on-disk cache.
Before this release every nexo update that bumped version.json wrote mcp-restart-required.json and forced every connected MCP client (Claude Code, Codex, Claude Desktop) to restart its session, even when the release was byte-identical to the running code at the Python level (cf. v7.10.1, a README-only release that still triggered a forced restart for everyone). The runtime now computes a sha256 over every .py file under src/ that the live server can import (excluding scripts/, tests/, migrations/, crons/, __pycache__/, node_modules/, .git/) and only writes the marker when that fingerprint changes between the pre-update and post-update trees. README-only / blog-only / changelog-only releases now skip the marker entirely; nexo update reports "MCP source unchanged (no .py byte changed) — no restart needed.". New helpers in src/runtime_versioning.py: compute_mcp_runtime_fingerprint, installed_runtime_fingerprint, prime_process_fingerprint, installed_force_restart_flag plus module-level PROCESS_FINGERPRINT primed at server startup. resolve_restart_required now uses fingerprint match as the primary signal and falls back to the legacy version-string mismatch only when the fingerprint cannot be computed. mcp-restart-required.json schema bumped to v2 with optional from_fingerprint / to_fingerprint; the v1 marker reader stays backwards-compatible. Conservative fallback honored (#186): missing fingerprint on either side → treat as code-changing and force restart. Explicit opt-in escape hatch via "force_restart": true in version.json for releases the fingerprint can't see (e.g. wire format of a config file read via json.load); reason becomes brain_update_force. nexo mcp-status --json now exposes installed_fingerprint, process_fingerprint, fingerprint_match. 14 new tests in tests/test_runtime_fingerprint.py plus 4 new packaged-update tests covering the npm path. Full write-up in docs/runtime-fingerprint.md.
Removes a residual Custom LLM endpoint (advanced) section (around line 1096 of README.md) that still documented llm_endpoint.json / auth_provider.json as a current feature, including the Idempotency-Key proxy semantics and a pointer to the now-deleted docs/api/override-files.md. The 7.10.0 code revert was complete; the README cleanup landed here. The repo-wide grep that 7.10.0 advertised as 0-hits is now actually 0-hits in the published npm tarball as well, not just in the source tree.
Reverts the override path introduced in 7.9.28 → 7.9.34. Background: 7.9.28 added two opt-in files at ~/.nexo/config/llm_endpoint.json and ~/.nexo/config/auth_provider.json that let a third-party orchestrator (NEXO Desktop) redirect every Anthropic SDK call from Brain to a custom proxy and resolve the bearer via a local helper, with concrete model names translated to wire aliases (nexo-max, nexo-high, nexo-medium, nexo-low, nexo-mini) and an Idempotency-Key per request. NEXO Desktop's commercial model has changed: Desktop is now a wrapper over the user's own Claude Code subscription (Max / Pro), with a separate Desktop licence. Brain calls go directly to api.anthropic.com using the user's existing OAuth (the one stored under ~/.claude/ and consumed by Claude Code spawns) or a plain ANTHROPIC_API_KEY. There is no NEXO bearer, no NEXO proxy, no NEXO credit accounting in this codebase. Removed: every override symbol from src/call_model_raw.py; the entire _apply_llm_endpoint_override helper from src/agent_runner.py and every call site; docs/api/override-files.md; tests/test_call_model_raw_overrides*.py and tests/test_agent_runner_override_env.py. Pre-existing override files on disk (if any operator has them) are simply ignored from this release forward.
Patch over v7.9.33 with two fixes. First, src/scripts/nexo-email-monitor.py::_parse_email_headers was silently dropping any email whose RFC822 headers came back as email.header.Header instances rather than plain strings — common for Q-encoded utf-8 / quoted-printable headers (display names with accents, subjects with non-ASCII). msg.get("Message-ID").strip() raised TypeError: 'Header' object is not subscriptable, the exception was swallowed at log.debug, and the email was discarded. Operators only noticed because Nero stopped replying. v7.9.34 routes every msg.get(...) through _decode_header (which decodes Q-encoding AND coerces to str), and lifts the failure log from DEBUG to WARNING. Second, src/hooks/pre_tool_use.py Guardian gate (Block K, G3 destructive / G3 SSH / G4 guard_check) emitted permissionDecision: deny JSON on a hard-mode block but exit 0 — terminal Claude Code occasionally proceeded with the next tool anyway because the JSON deny was being dropped or out-of-order delivered mid-tool-loop. Hard blocks now also write the structured Guardian reason to stderr and exit 2, the documented PreToolUse blocking exit. Belt-and-suspenders: model receives the Guardian reason through both channels and self-corrects instead of blindly retrying. 5 new parser tests + 2 hardened hook tests.
Patch over v7.9.32. Hotfix for Bandit B324 finding in src/scripts/nexo-email-monitor.py::_email_checkpoint_path. The hash is purely a filename disambiguator (Message-IDs contain characters the FS rejects), not a cryptographic primitive. v7.9.33 adds usedforsecurity=False to the SHA-1 call so Bandit accepts the non-security usage. The v7.9.32 git tag is preserved for traceability but no npm artifact ever shipped for it; this is the first npm release that carries the 7.9.32 email-recovery checkpoints.
Patch over v7.9.31. Hardens email-monitor recovery against cascades of Brain releases. Background: a single email can fall between several Brain updates in a tight window (4 releases on 2026-04-26 alone), and the previous 24-hour ``_recover_unreplied_processed`` sweep let those drop into a permanent limbo because the next sweep happened after the email had already aged out. v7.9.32 widens the lookback to 7 days (168h) and introduces per-email checkpoints at ~/.nexo/nexo-email/checkpoints/ that capture files the failed attempt touched, the last assistant narration extracted from Claude Code's JSON output, and the error. Retry attempts inject that context into the next prompt so a long task (drafting a presentation, multi-step analysis, building a report) continues from where the previous attempt died instead of restarting from scratch and duplicating tokens. Stale checkpoints are pruned automatically after 7 days. 15 new unit tests in tests/test_email_monitor_checkpoints.py pin the helpers.
Patch over v7.9.30. Detected during real wire smoke and surfaced by an external auditor. call_model_raw was sending stop_sequences=["\n", ".", " "] by default, which the current Anthropic Messages API rejects with HTTP 400 each stop sequence must contain non-whitespace. Every enforcer_classifier call running on the default was failing in production and the conservative fallback was silently kicking in. v7.9.31 changes the default to None (no stop_sequences field sent on the wire) since max_tokens=3 already serves as the hard cap for yes/no classification, and adds a local guard that raises ClassifierUnavailableError when a caller passes whitespace-only or non-string entries instead of letting the API 400 the request remotely. Two new e2e wire tests and three new unit tests pin the behaviour. This release also removes an internal design document from the open-source distribution.
Patch over v7.9.29. Hotfix for a missing import sys in src/agent_runner.py that ruff F821 caught in CI tests/test_fase4_lint_baseline.py::TestRuffPasses::test_ruff_check_src_returns_zero. The 7.9.29 ``_apply_llm_endpoint_override`` helper introduced a sys.stderr.write(...) call but the module did not import sys, so the publish workflow failed before reaching the npm publish step. v7.9.30 adds the import; this is the first npm release that carries the 7.9.29 override-path hardening (Authorization Bearer, call-time config dir, caller-controllable Idempotency-Key, strict bearer source).
Patch over v7.9.28. Fixes four issues an external audit caught after the 7.9.28 release: (1) the bearer is now passed to the Anthropic SDK via auth_token so it serialises into Authorization: Bearer instead of X-Api-Key — any compatible proxy that only accepts the standard OAuth header was rejecting every request with 401. (2) The Brain config directory is resolved at every call to _read_versioned_config instead of cached at module import, so LaunchAgent crons that export NEXO_HOME from a wrapper now reach the right ~/.nexo/config/. (3) Idempotency-Key accepts a caller-provided value so application-level retries reuse the same dedup key and the proxy treats them as duplicates instead of brand-new billable requests. (4) Override mode is now strict about its bearer source: if auth_provider.json is absent or its helper fails, the call raises ClassifierUnavailableError instead of falling back to the operator's real ANTHROPIC_API_KEY — combined with neutralising the SDK env-var fallback during construction, this prevents a real sk-ant- value from leaking to a custom proxy. New tests/test_call_model_raw_overrides_e2e.py drives the real SDK against a local http.server and asserts on captured wire headers and body, complementing the SDK-mock unit tests.
Patch over v7.9.27. Two optional JSON files at ~/.nexo/config/llm_endpoint.json and ~/.nexo/config/auth_provider.json let third-party orchestrators (Anthropic-compatible proxies, internal gateways) redirect Brain SDK calls and delegate bearer token resolution to a local command, analogous to git's credential.helper. The redirection covers both the SDK direct path (call_model_raw.py) and every CLI child Brain spawns (agent_runner.py) so headless crons — deep-sleep, evolution, followup-runner, morning-agent, email-monitor — hit the proxy too. LaunchAgent processes do not inherit env from a UI process, so the redirection has to come from inside Brain. An Idempotency-Key (UUID4 hex) is attached per request for proxy-side dedup of transparent retries within 24h. Brain libre standalone (no override files) hits api.anthropic.com directly with ANTHROPIC_API_KEY exactly as before.
Patch over v7.9.26. Server startup no longer hangs the MCP initialize handshake when legacy followups/reminders still need owner backfill. The synchronous startup migration now invokes scripts/backfill_task_owner.py --rules-only, skipping the multi-minute LocalZeroShotClassifier (mDeBERTa) load that previously timed out the 60s subprocess gate and left every restart looping over the same legacy rows. Subprocess timeout reduced to 30s now that the regex path completes in milliseconds. Worst case ambiguous rows fall back to 'shared'; Deep Sleep / cron can later re-run without --rules-only to refine those rows with the classifier.
Patch over v7.9.25. Headless automation prompts now receive the operator-language contract centrally in run_automation_prompt, so reports, diaries, syntheses, followups, escalations, and Deep Sleep-generated memory text follow calibration.json even when the underlying template is English. Deep Sleep extract/synthesize prompts now rely on that deterministic runner contract instead of asking the model to find calibration opportunistically.
Patch over v7.9.24. Managed Claude Code and Codex bootstraps now include a shared User-Facing Agent Contract for the configured assistant identity, continuity checks before denying prior work, professional autonomy, safety boundaries, and calm user-facing tone. Desktop carries a shorter equivalent reminder for normal conversations.
Patch over v7.9.23. Desktop lifecycle fallback diaries now prefer the registered NEXO session over newer alias-only rows, and nexo lifecycle stop-nexo-session resolves orphan aliases back to their registered sibling sessions before calling nexo_stop. App-exit can therefore preserve the diary and confirm the real active session closed.
Patch over v7.9.22. Desktop lifecycle fallback diaries now enrich sparse close/archive/app-exit payloads from durable continuity_snapshots, preserving recent turn context in the emergency session_diary instead of only writing a generic close note when the live shutdown prompt times out.
Patch over v7.9.21. Desktop lifecycle events now have a Brain-side emergency diary path: if the live agent does not answer the close/archive/app-exit diary prompt, Brain can write a desktop-lifecycle-fallback session_diary from the lifecycle snapshot instead of losing the shutdown context. The fallback preserves title, current goal, session ids, and transcript tail for later recovery.
Patch over v7.9.20. LaunchAgent reload and runtime doctor repair now tolerate macOS already-loaded races by booting out jobs by label and plist path, falling back to legacy launchctl load -w, and treating Bootstrap failed: 5 as success only when launchd confirms the job is loaded from the expected plist.
Patch over v7.9.19. Packaged update and runtime doctor repair now resolve cron sync from ~/.nexo/runtime/crons/sync.py, LaunchAgent PATH includes the managed Claude runtime under ~/.nexo/runtime/bootstrap/npm-global/bin, runtime root backfill includes claude_cli.py, and Immune skips the optional legacy ~/.claude-mem/claude-mem.db when absent.
Patch over v7.9.18. Runtime doctor now separates current product health from work still in progress, excludes interactive Desktop sessions from automation telemetry scoring, prunes stale filesystem-backed skills, downgrades missing executable skill definitions to guide mode, marks stale drained protocol debt as resolved, and treats watchdog SIGTERM 143 exits as supervisor reloads instead of cron failures.
Patch over v7.9.17. bootstrap_docs.py now defines _user_home() before resolving module-level template paths, so nexo clients sync, packaged update client-sync checks, and doctor bootstrap checks no longer crash when NEXO_HOME is unset.
Patch over v7.9.16. Continuity snapshot idempotency uses SHA-1 only as a stable deterministic key, not for security. The call now sets usedforsecurity=False, keeping the high-severity Bandit gate green without changing existing idempotency semantics. This release includes the v7.9.16 restart-marker deadlock fix and is the publication target for npm.
Patch over v7.9.15. Brain restart-required markers now include only the active interactive clients configured for the user instead of hardcoding Claude Desktop, Claude Code, and Codex as mandatory acknowledgers. nexo_startup remains reachable while a restart marker exists, and the MCP middleware auto-acks the identified client once the installed runtime and process runtime versions match. This prevents the post-update deadlock where users without all three clients, or clients missing NEXO_MCP_CLIENT, could be blocked from every normal NEXO MCP call after update. The release also keeps release artifacts and public surfaces aligned with the package version before npm publication.
Patch over v7.9.14. Brain registers the semantic reasoner caller, persists cortex decision critique metadata for high-stakes decisions, and pins local embedding/model choices through a manifest-backed resolver used by warmup and migration paths.
Patch over v7.9.5. Brain now persists conversation-scoped continuity snapshots and resume bundles keyed by conversation_id + session_id, with fail-closed unsafe_sid handling when it cannot prove that a restore belongs to the current conversation/client. The packaged runtime now installs under ~/.nexo/core/versions/<version> and activates through the atomic ~/.nexo/core/current pointer, so nexo update no longer overwrites code under a live MCP process. Real version changes write a durable mcp-restart-required.json marker, nexo mcp status exposes the installed/process split, and old MCP processes self-drain with structured mcp_restart_required responses until the client restarts against the installed runtime. This closes the installed-user update contract for both brain-only and coordinated brain+desktop installs without shipping a separate stdio supervisor in this architecture. Validation: targeted Brain continuity/runtime suite (27 passed) plus coordinated Desktop full suite (727 pass, 0 fail, 1 skipped).
Patch over v7.9.4. Brain now resolves Desktop/Claude session UUIDs through session_claude_aliases and sessions before checking session_diary. This fixes the real archive/app-exit failure where the canonical prompt wrote the required diary under the active nexo-... SID while diary confirmation kept polling the Desktop UUID and timed out. The diary high-water checkpoint also includes alias-linked NEXO SIDs, so old manual or previous canonical diary rows cannot satisfy a new lifecycle event. Validation: pytest tests/test_lifecycle_events.py (28 passing) plus coordinated Desktop v0.28.6 archive/delete/app-exit checks.
Patch over v7.9.3. Brain canonical lifecycle plans now require real session_diary evidence before stop_session and before Desktop archive/delete/close/window-close/app-exit can complete. The v3 plan runs resume_session → inject_prompt → wait_for_diary_write → stop_session, records a diary checkpoint at dispatch, rejects canonical completion without a diary row after that checkpoint, and keeps the event retryable/idempotent instead of treating inject timeout as success. The npm CLI also stops opening stdin for --version, --help, and known subcommands when calibration is valid; legacy calibration with real user.name + user.language is accepted, and setup commits calibration.json atomically only after the wizard completes. New nexo-brain warmup-models predownloads the pinned mDeBERTa classifier, BGE embeddings, and fastembed reranker during install/update. Validation: full Brain pytest (2189 passed, 3 skipped, 1 xfailed, 5 xpassed), release-readiness, npm pack dry-run, and coordinated Desktop v0.28.3 checks.
Patch over v7.9.2. Brain's canonical lifecycle plan now publishes the action shape Desktop needs for reliable close/archive/delete/app-exit diary execution: type is the canonical action discriminator and the diary prompt lives in payload.prompt. The old kind and top-level prompt fields remain for one release as compatibility mirrors, so Desktop clients up to v0.28.1 keep working while v0.28.2 consumes the normalized contract. canonical_plan_version is bumped to 2. Tests pin resume_session → inject_prompt → stop_session action shape, payload prompt round-trip, and app-exit parity. Targeted validation: pytest tests/test_lifecycle_events.py (25 passing), release artifact sync, and release-readiness.
Patch over v7.9.1. Brain's remaining semantic decision callers now route through semantic_router.route(...) with named decision_kind policies instead of each file owning local classifier or LLM fallback policy. The migrated decisions are r20_constant_change, r34_identity_coherence, t4_r15, t4_r23e, t4_r23f, t4_r23h, followup_operator_attention, drive_signal_type, drive_area, reply_event_type, query_intent, and sentiment_intent. Structural fallbacks remain where they protect degraded operation, but Brain's router owns model choice, thresholds, and fallback behaviour centrally. Runtime audit also found a packaged-headless bug: tool-enforcement-map.json existed under ~/.nexo/core, while the Python loaders never checked the installed core directory. enforcement_engine._load_map() and agent_runner._build_enforcement_system_prompt() now check Path(__file__).parent / tool-enforcement-map.json, so followup-runner, morning-agent, digest, email-monitor, and other packaged headless jobs load the Guardian map instead of logging No enforcement map found. Tests: 100 semantic/router/enforcer tests, 125 Drive/cognitive/productization tests, and release-readiness passing.
Patch over v7.9.0. The semantic stack is now used by the first safe conversational group instead of sitting as scaffolding only. session_end_intent.py, r14_correction_learning.py, r16_declared_done.py, r17_promise_debt.py, autonomy_mandate.py, and guard_verbal_ack.py call semantic_router.route(...) with explicit decision_kind values and semantic labels. Existing test seams remain intact: callers still accept an injected classifier where they did before, so unit tests and specialized harnesses do not need to boot the router. The router and semantic_reasoner local paths also now classify the live context first, falling back to the prompt only when context is empty; this prevents static prompt wording from creating false positives such as a correction sentence being interpreted as a session-end request. Tests: 105 targeted passing across router, reasoner, site-migration, and the six migrated caller suites.
Minor release under the ONEPASS LLM Coverage plan. New src/semantic_router.py is the central router for every model-backed semantic decision in Brain: 18 named decision_kinds (13 textual + 5 code-aware), a RouterResult dataclass, and the per-kind policy-driven layer chain fast_local → semantic_reasoner → remote_fallback. New src/semantic_reasoner.py introduces two modes: Mode A (multipass_local) reuses the already-pinned LocalZeroShotClassifier (same MoritzLaurer/mDeBERTa-v3-base-xnli-multilingual-nli-2mil7 pin from classifier-model-notes.md) with three prompt-perturbed passes, majority vote, and a stricter 0.75 confidence floor — no new model download, just stricter aggregation; Mode B (cached_llm) wraps call_model_raw with a pid+uuid atomic-write disk cache under ~/.nexo/runtime/operations/semantic-reasoner-cache.json, SHA-256 keyed by (decision_kind, normalized_question, normalized_context, labels), 24h TTL, LRU-bound at 2000 entries, corrupt entries dropped on read. New scripts/semantic-classify.py JSON-in JSON-out CLI lets external MCP clients (including the closed-source NEXO Desktop companion) query Brain as the single semantic authority. New NEXO_SEMANTIC_REASONER kill switch (0/off/false/no/disable/disabled) honours the ONEPASS plan mandate for a dedicated runtime opt-out, separate from NEXO_LOCAL_CLASSIFIER (which only gates install-time provisioning). Two product-bug fixes: bin/nexo-brain.js upgrade flow now copies templates/ root the same way fresh install and same-version refresh already did (Maria iMac upgrade 7.1.10→7.8.1 had lost 27 core-prompts templates and broken post-update import verification); and tool-enforcement-map.json nexo_startup.enforcement.inject_prompt now instructs the model to preload the 13 mcp__nexo__* protocol tools via ToolSearch before calling nexo_startup when the MCP host defers tool schemas (Claude Code with many MCPs installed), closing the silent-bootstrap-failure mode observed live in session nexo-1776899231-34499. Audit-driven hardening from the 4-auditor pre-release review: router/reasoner use getattr over the call_model_raw module and catch plain Exception as a trailing clause so provider errors (APIError, TimeoutError, KeyError) degrade with error="remote_error: <cause>" instead of propagating; cache writes use pid+uuid temp + fsync + os.replace to survive concurrent Brain+Desktop-CLI writers; NEXO_SEMANTIC_REASONER_TTL parse tolerates malformed values with a logger warning + default fallback. Tests: +50 (22 router, 20 reasoner, 8 CLI). Per-site migration of existing callers (session_end_intent, r14, r16, r17, r20, r34, T4 gates, tools_drive, nexo-followup-runner) is explicitly deferred to follow-up patch releases under NF-SEMANTIC-ROUTER-SITE-MIGRATION; nothing in this release changes the behaviour of the existing callers. Companion coordinated release: NEXO Desktop v0.28.0.
v7.8.0 and v7.8.1 closed the compaction restore path and the Layer-2/3 emergency-diary SID targeting. Francisco audited the resulting telemetry and flagged one remaining hole: hook_runs.session_id was empty for 7 out of 8 recent compaction rows, and when populated it stored the raw CLAUDE_SESSION_ID token instead of the NEXO sid — per-session joins over hook_runs were therefore useless for compact events. v7.8.2 adds src/hooks/compact_session_resolver.py with resolve_nexo_sid(claude_session_id), which walks the same rails the shell already uses: sessions.claude_session_id match, then session_claude_aliases.claude_session_id (most recent last_seen wins), then the per-conversation sidecar under runtime/data/compacting/<safe-claude-id>.txt, then the legacy global sidecar for single-conversation setups. Returns (nexo_sid, source) so callers can stash source in hook_runs.metadata for empty-row triage. src/hooks/pre_compact.py and src/hooks/post_compact.py now call the resolver and store the real NEXO sid in hook_runs.session_id; both wrappers also stash {claude_session_id, sid_source} in hook_runs.metadata so "why is this row still empty?" has a one-query answer. Nine new tests in tests/test_hook_runs_compact_sid_resolution.py pin the five resolver rails (sessions / alias / sidecar / legacy / none), malformed-sidecar rejection, the pre- and post-compact wrapper end-to-end paths, and the empty-state wrapper rail so a clean audit trail is written even when nothing resolves. Pytest remains green. No Desktop bump.
v7.8.0 closed the main compaction restore path (checkpoint sidecar, post-compact fail-closed on SID mismatch, per-session queue). Francisco flagged one last hole: pre-compact.sh's Layer 2 emergency auto-diary and Layer 3 compaction_memory.record_auto_flush were still querying SELECT sid FROM sessions ORDER BY last_update_epoch DESC LIMIT 1 — "latest active session". In multi-conversation Desktop that routinely wrote the emergency diary against the WRONG conversation even though the main restore was already exact-SID. v7.8.1 changes both layers to use the TARGET_SID already resolved from CLAUDE_SESSION_ID, scopes last_diary_ts by session_id, and fails-closed when no SID resolves (skipping the emergency diary is better than writing against the wrong conversation). Two new behavioural tests drive the real shell script against a fixture DB with two sessions where the "latest" is NOT the target — pre-v7.8.1 regressions would write against the wrong SID, the new behaviour writes against TARGET_SID. Adding the tests surfaced a latent bash-escape bug: a double-quoted phrase inside a Python comment embedded in a python3 -c "..." heredoc silently closed the argument early, so the entire Layer-2 block had been no-oping in production on the first hook run. The comment was reworded to remove any bash-meta characters. Pytest 2092 passing (+2 new behavioural). No Desktop bump.
v7.7 shipped pass 2 of constructor-guardian-90. v7.8 closes the PostCompact work Francisco flagged right after: src/hooks/post_compact.py is now a real registered hook (the canonical set grows from 8 to 9, both in src/hooks/manifest.json and hooks/hooks.json; test_manifest_has_nine_hooks pins the floor). pre-compact.sh resolves the NEXO SID from CLAUDE_SESSION_ID via sessions.claude_session_id + session_claude_aliases — the pre-v7.8 LATEST_SID fallback was actively wrong in multi-conversation Desktop (it compacted whichever conv was touched last, not the one Claude Code actually compacted). The sidecar moves from /tmp/nexo-compacting-sid to $NEXO_HOME/runtime/data/compacting-sid.txt so two concurrent compactions on two conversations cannot race on /tmp. post-compact.sh removes the "latest checkpoint" fallback: fail-closed with a small "SID mismatch" / "no checkpoint for this exact session" systemMessage instead of restoring the wrong conversation. It also cross-checks the sidecar SID against the env-resolved one and refuses the restore on mismatch. Pre- and post-compact now append one NDJSON row per event to pending_enforcer_events.ndjson; the engine's new _consume_pending_hook_events() drains the queue on every periodic tick and fires the matching on_event rule — the map's pre_compaction / post_compaction triggers finally fire from the live stream, not only via tests. The queue file is truncated after read so a row never fires twice. compaction_count is pinned to increment only inside the real-restore branch (a test now catches if a refactor moves it into the fallback path). New contract test tests/test_v78_compaction_continuity.py (11 invariants across all ten rails). Pytest 2086 passing (+16 vs v7.7). No Desktop bump — v7.8 is entirely server/hooks-side.
v7.6.0 shipped contract parity (all eight rule types dispatched by both engines) and four default-mode bumps, but listed six gaps as honestly still-partial. v7.7.0 closes them. Gap 1: autonomous detector for multi_step_task_detected — three recent Edit/Write/Task calls without a prior nexo_skill_match now raise the event automatically through raise_event() (v7.6 exposed the API but nothing invoked it). The latch clears on both nexo_skill_match and nexo_task_close. Gap 2: the R16 classifier prompt (templates/core-prompts/r16-declared-done-question.md) now matches sent / delivered / published / deployed / released / fixed / resolved / merged / pushed plus Spanish equivalents, so the on_event trigger done_claimed_with_open_task fires on the full close-claim vocabulary the checklist called out. Gap 3: R_CATALOG extends its trigger set beyond nexo_*_create/_open/_add to plain Edit/Write into artefact-bearing paths (skills/, plugins/, personal/scripts/, templates/core-prompts/, …). Discovery set grows from 6 to 8 (adds nexo_personal_scripts_list + nexo_plugin_list). Gap 4: new runtime rule R_PRIMITIVE_CHOICE (module src/r_primitive_choice.py) gates Edit/Write of a brand-new artefact file without a recent primitive-choice probe — SK-CREATE-NEXO-PRIMITIVE becomes enforcement-backed instead of advisory. Disjoint from R_CATALOG: R_CATALOG fires on every artefact-path write without inventory consultation; R_PRIMITIVE_CHOICE fires only when the file is actually new. Gap 5: guardian_default.json v1.5.0 raises R11_plugin_load_pre_inventory soft → hard and adds the new rule at soft so its FP rate can be observed. Gap 6: new tests/test_v77_enforcement_gaps.py pins 12 invariants across all six rails. Pytest 2070 passing (+14 vs v7.6). Companion release: NEXO Desktop v0.27.0 mirrors the guardian default bumps (no new dispatch changes beyond v0.26).
v7.6.0 closes the drift between tool-enforcement-map.json v2.2 and the two enforcement engines. Before this release the Brain engine (src/enforcement_engine.py::_build_indexes) silently ignored before_tool, on_event, and conditional rules even though the map declared them — so Brain users got the weaker contract while Desktop honoured them correctly. The v7.6 engine dispatches all eight rule types declared by fase2_schema.supported_rule_types_v2_0. The public API gains on_tool_call_before(raw_name, tool_input), raise_event(event_name, context), and reset_task_cycle(tool) so hooks can fire semantic events (multi_step_task_detected, done_claimed_with_open_task, user_correction_without_learning, post_compaction, …). after_tool satisfaction is now per-instance (monotonic _tool_instance_counter) — the previous check (target not in self.tools_called) silently satisfied the dependency forever after the first historical target call, a defect explicitly flagged by the constructor-guardian-90 checklist. Map v2.2 tightens two triggers: nexo_learning_add on_event grace_messages: 3 → 0 (corrections produce the learning in the same turn) and nexo_task_open conditional threshold: 10 → 4, level should → must, plus an explicit inject_prompt. guardian_default.json v1.4.0 hardens R15_project_context, R17_promise_debt, R22_personal_script and R_CATALOG_before_artifact_create from soft to hard, and moves R34_identity_coherence from shadow to soft so identity denials surface a visible reminder instead of silent telemetry. New contract test tests/test_v76_map_parity.py (6 cases) pins the invariants: every declared rule type is dispatched by both engines, fase2_schema cannot lie about support, task_open threshold ≤ 5 + inject_prompt present, learning_add grace 0, Brain exposes the new public API, after_tool uses per-instance comparison (source inspection). Pytest 2056 passing (10 unrelated pre-existing failures tracked separately). Companion release: NEXO Desktop v0.26.0 mirrors the engine fixes + default hardening.
v7.5.0 promotes nexo_lifecycle_event from ledger + reconciliation authority to canonical authority of session-end. Brain now owns the prompt, the sequence, and the timing of diary+stop; NEXO Desktop v0.25.0 (closed-source companion at nexo-desktop.com) is the conduit that executes Brain's plan against the live Claude process stdin. The new 2-call contract — nexo_lifecycle_event returns a versioned canonical_plan (resume_session → inject_prompt → stop_session, with stable ids and per-action timeout_ms) and the new nexo_lifecycle_complete_canonical confirms execution with a per-action results array — replaces polling with explicit acknowledgement. canonical_plan_id is deterministic: sha256(event_id + "|v" + plan_version)[:24], so retries reuse the same id and clients deduplicate by (event_id, canonical_plan_id). Schema migration m52 extends lifecycle_events with six canonical_* columns plus an index; pre-v7.5 rows simply carry NULL. session_diary is the dedupe key on re-delivery: if Desktop crashes between executing the inject and sending the complete call, the next nexo_lifecycle_event call for the same event_id inspects session_diary for a row written after canonical_dispatched_at; if one exists, Brain short-circuits to already_processed and refuses to re-dispatch. Seven explicit delivery_status values (accepted / processed / canonical_pending / canonical_done / already_processed / retryable_error / rejected) give the pipeline a diffable state machine. switch and window-close stay observational (no plan ever issued, even with a live session_id). nexo lifecycle record exit code 0 now covers canonical_pending; older wrappers that treated it as an error are incompatible with v7.5. Tests: 24/24 lifecycle canonical green (plan_id determinism, complete-canonical branches, redelivery after canonical_done, session_diary dedup, retry-after-failed-inject, JSON round-trip). Full pytest suite 2050 passing, 10 pre-existing failures unrelated to v7.5. Total MCP tools 262 → 263.
v7.4.1 corrects the over-promise in the v7.4.0 release notes and locks in the exact role of nexo_lifecycle_event: a ledger + reconciliation authority, NOT the canonical executor of diary+stop. Diary+stop injection still happens in Desktop's closeConversationGraceful (the only place that writes to the live Claude process's stdin). Moving that responsibility to Brain requires a Brain↔Claude-session bridge that does not exist yet and is scheduled for v7.5 (followup NF-V75-CANONICAL-DIARY-AUTHORITY). The paired Desktop v0.24.1 wires the remaining switch / window-close / app-exit transitions through the same durable service, adds an NDJSON telemetry trail keyed by event_id (kinds: enqueued, sent, acked, retry, reconciled, failed), and an exponential backoff schedule in the reconciler (2s, 8s, 30s, 2m, 10m, 30m, 1h, 2h, 4h, 8h). Brain needed no code change for any of that — the ledger already accepted every action from day one. No schema migration in this patch; the lifecycle_events table shipped by migration m51 in v7.4.0 already covers all six actions. VALID_ACTIONS stays frozen at close / delete / archive / switch / app-exit / window-close, enforced by a contract test. Total MCP tool count unchanged (262).
nexo_lifecycle_event + idempotency + Desktop durable queue
v7.4.0 ships the Brain-side of the guardian-claude-desktop-plan.md pipeline that NEXO Desktop v0.24.0 now depends on. Every conversation lifecycle transition on Desktop (close / delete / archive / switch / window-close / app-exit) is persisted to a durable queue BEFORE any UI mutation becomes visible and then relayed to Brain through nexo_lifecycle_event for canonical processing. Re-delivery of the same event_id returns already_processed without re-running any side effect — strict idempotency per "5. Idempotencia real" in the plan. Companion nexo_lifecycle_status(event_id) exposes the stored row for Desktop's boot-time reconciliation. Backed by the new lifecycle_events table (migration m51) keyed by event_id with columns action, conversation_id, session_id, reason, payload_snapshot, delivery_status, retry_count, created_at, processed_at, last_error. A nexo lifecycle record / nexo lifecycle status CLI subcommand lets Desktop bridge through runNexoCommand without any new IPC surface; exit codes 0/2/3 map onto terminal / retryable / rejected acks. 12 new contract tests pin idempotency, diary-triggering action flags, malformed input rejection paths, payload roundtrip, and the frozen VALID_ACTIONS set. Total MCP tools 260 → 262 (verify_tool_map.py passes). No breaking changes; install coordinates automatically via nexo update.
Hotfix minor release correcting three critical bugs that surfaced right after v7.2.0. B11 Guardian wire: new src/hooks/pre_tool_use.py entrypoint is now registered in src/hooks/manifest.json and hooks/hooks.json so the Claude Code PreToolUse event actually reaches Guardian — before this, guardian-runtime-overrides.json in hard mode was silently inert for G3-destructive, G3-SSH, and G4-guard_check gates. A parallel SSH prescreen in hook_guardrails.process_pre_tool_event forces op=write on remote-write patterns the local shell classifier could not see. B10 post-sync: _run_post_install_hooks_fresh(dest, env) invokes each whitelisted hook (_persist_guardian_hard_defaults, _maybe_promote_adaptive_weights_empirically) in a clean subprocess against the newly copied tree, so the first nexo update that introduces a new post-install hook actually runs it — previously the hook dispatch used the pre-upgrade module held in memory and silently no-op'd. B12 map distribution: tool-enforcement-map.json is now part of the npm files whitelist so fresh npm install -g nexo-brain ships it, closing the three-way gap (Brain npm + Desktop bundle + runtime sync) that prevented Desktop from ever discovering the map on new installs. PE1 rapid items: 5 additional destructive_command presets in src/presets/entities_universal.json (curl_pipe_shell, dd_to_device, chmod_recursive_wide_open, ssh_remote_overwrite, scp_rsync_upload; coverage floor raised from 7 to 12) and the guardian-metrics daily cron at 02:15 that feeds Fase C gate and the Guardian Proposals panel. Desktop v0.23.0 ships the renderer-side half of B12 plus B13/B14 (the "Parar → Enviar cola" recovery loop).
Minor release consolidating three parallel workstreams into a single Guardian-active-by-default train. Block K closure: G1 enforcer (PostToolUse nudge when nexo_task_open returned mode ∈ {defer, ask, verify} without the paired next_action), G3 SSH remote-write detector (catches ssh host "cat > ...", scp upload, rsync upload, sftp -b batch and 10+ other patterns the local destructive gate never saw), new src/guardian_runtime_config.py resolver unifying gate modes (env > ~/.nexo/personal/config/guardian-runtime-overrides.json > default), and _persist_guardian_hard_defaults during nexo update so every non-ephemeral install gets Guardian in hard without env vars. F0.6 hardening: nexo rollback f06 CLI with two-stage safe swap, src/scripts/prune_runtime_backups.py promoted from personal to core, authoritative docs/f06-layout-contract.md, three new doctor boot-tier checks (check_core_dev_packaged_install, check_dashboard_desktop_contract, check_f06_migration_consistency), scripts/nexo-migrate-nora.sh + scripts/f0-safe-apply-remote.sh idempotent migration workflow, v6.x→F0.6 rollback hardening tests. Adaptive weights: flips from "14-day calendar" to "14 days OR (≥200 samples AND ≥2 days)" + _maybe_promote_adaptive_weights_empirically auto-promotes shadow→learned during nexo update so mature installs feel Cortex calibration immediately. Small fixes: R34 bool("unknown")==True corrected, classify_scripts_dir dedup by realpath, B10 module-level path constants lazy-evaluated in public_contribution.py / tools_sessions.py / plugins/recover.py / plugins/update.py, schedule-override audit log at runtime/logs/core-schedule-overrides.log, scripts/pre-release-verify.sh + docs/release-discipline.md, pre-commit hook for tool-enforcement-map.json drift. Desktop v0.22.6 compatible; MCP external contract unchanged.
checkpoint_policy + smoke-artifact release verifier
Follow-up over v7.1.8. Ships two rescue batches of WIP that were stashed aside during the v7.1.8 release window. First rescue: src/autonomy_mandate.py expands the mandate-detection vocabulary (hazlo todo / no pares / estás al mando / te dejo al mando / sigue sin parar / haz el plan completo), adds three honest flags on MandateState (execute_until_blocker, suppress_mid_task_menus, revalidate_after_compaction) with session filtering, wires post/pre-compact hooks that read those flags, surfaces them through protocol/workflow handlers and session payload, and introduces the new src/checkpoint_policy.py module with tests. Second rescue: scripts/verify_release_readiness.py gains a smoke-artifact contract pass that validates release-contracts/smoke/v<version>.json before any tag push, the release-final audit skill references the new contract, src/hook_guardrails.py + src/hooks/post_tool_use.py refine the post-tool protocol reminder path with a new contract test, and a couple of core prompts (task-close evidence, r14 correction learning) get wording polish.
Batch over v7.1.7. Deep Sleep phase auto-drains stale protocol_debt rows (G2). New pre-tool gates block destructive Bash shapes (G3) and enforce nexo_guard_check before Edit/Write (G4), both shadow-by-default via env flags. nexo_task_open accepts inline ack_rules (G7). Session briefing emits a Guardian Health section with open-debt totals + failing hooks (G8). backfill_task_owner routes intent through the local zero-shot classifier; migration v50 supersedes the duplicate NEXO-product learning pair. LaunchAgent plist protection, francisco_emails export removed, runner-health-check.py + nexo_personal_automation.py promoted to core.
Patch over v7.1.6. src/scripts/nexo-email-monitor.py now carries the calibrated operator language through its prompt contract and localizes direct needs_interactive escalation subjects/bodies. Result: Spanish operators stop receiving fallback English monitor mail when the daemon needs to escalate a thread for manual attention.
Patch over v7.1.5. Brain now exposes dedicated cadence overrides for structural core crons via schedule-overrides.json, CLI/MCP surfaces, and runtime re-sync; Desktop consumes the same contract through a dedicated Core schedules tab; and the shipped com.nexo.synthesis.plist template/docs are realigned with the live 06:00 daily manifest again.
Patch over v7.1.4. src/scripts/nexo-catchup.py now lazy-loads the interactive automation helpers so direct runtime-root catchup runs stop failing on lean installs, src/product_mode.py ignores the operator machine's globally installed Desktop app when evaluating an explicit external/test home, and src/cli.py preserves compatibility for legacy nexo_doctor script callers by defaulting the missing plane to installation_live.
Patch over v7.1.3. Real Desktop-managed installs revealed one last packaged updater hole: nexo update could still verify imports before the packaged runtime layout had recreated the root shim files. src/plugins/update.py now finalizes the layout first and only then runs import server verification, so self-contained installs stop failing their own post-update health-check.
Patch over v7.1.2. Desktop-managed Brain updates can now reuse the app-bundled npm runtime instead of assuming a separate global install, portable user-data bundles can be inspected before restore with version/section compatibility metadata, product_mode detection is tighter on explicit-home packaged installs, and the public release surfaces are refreshed again so the open-source Brain and coordinated Desktop line describe the same shipped runtime.
Patch over v7.1.1. The remaining startup, enforcement, project, and followup prompt fragments are now centralized under the shared prompt catalog; agent_runner.py and db/_email_accounts.py stop eager-loading prompt or DB state too early; deep-sleep/extract.py now passes the correct JSON system prompt; and the public release surfaces are refreshed so the open-source Brain and the coordinated Desktop line describe the same shipped runtime again.
Hotfix over v7.1.0. Packaged installs were still able to mistake ~/.nexo/core for a mutable source repo, and F0.6 compatibility shims (db, cognitive, skills-core, root Python modules, script/plugin links) could therefore break nexo update with copy collisions during replay or rollback. src/auto_update.py now distinguishes packaged runtime mode from true source-linked mode, and the runtime copy/restore path is shim-aware when replacing symlink/file targets. Result: packaged installs update cleanly again, and true source-sync installs keep working too.
v7.1.0 turns the F0.6 layout split into a stable runtime/product contract. Install/update flows now treat ~/.nexo/core as the canonical shipped code root and re-run layout healers after sync, Brain exports guardian-runtime-surfaces.json so Desktop stops drifting on live Guardian datasets, email-monitor/followup-runner/morning-agent become configurable core automations with explicit prerequisites and additive operator instructions, the email runtime model now distinguishes agent-vs-operator inboxes with permissions and default routing, and the local classifier baseline auto-installs on fresh installs and nexo update unless the operator explicitly opts out with NEXO_LOCAL_CLASSIFIER=off.
src/db/_core.py::DB_PATH era el único caller que seguía hardcoded a la ruta legacy pre-F0.6. Tras la migración F0.6 la DB vive en ~/.nexo/runtime/data/nexo.db, pero ese módulo seguía abriendo ~/.nexo/data/nexo.db (inexistente). Resultado: nexo email list, nexo scripts list, nexo_task_open y todo lo demás que comparte la conexión DB devolvían resultados vacíos. Fix: DB_PATH ahora es transition-aware (NEXO_TEST_DB y NEXO_DB env overrides mantienen prioridad).
Separación física del runtime en ~/.nexo/{core,personal,runtime}/. La estructura flat (scripts/, brain/, data/, operations/...) desaparece. Operadores en v6.x se auto-migran en primer nexo update a v7.0.0; fresh installs caen directos en la nueva estructura. Nuevo módulo src/paths.py centraliza cada path helper (core_scripts_dir, personal_scripts_dir, brain_dir, data_dir, db_path, ...) y todos son transition-aware: devuelven la ruta nueva si existe, caen al legacy si solo el legacy está presente. 24 archivos src refactorizados, 7 shell scripts actualizados, 71 personal_scripts.path rows UPDATEd transaccional, 40 LaunchAgent plists reescritos. 1551 tests pasan. El cliente NEXO Desktop v0.21.0 (closed-source distribuido aparte) actualiza también sus paths.
Tres verbos nuevos en el CLI: nexo scripts enable <name>, nexo scripts disable <name>, nexo scripts status <name> — todos aceptan --json para consumidores máquina (incluido el panel Automatizaciones del cliente NEXO Desktop, que es un producto separado closed-source). El wrapper del cron (nexo-cron-wrapper.sh) lee personal_scripts.enabled en cada tick: cuando está desactivado sale con exit 0 y summary='[disabled]' mientras el LaunchAgent sigue cargado, así reactivar es un solo comando. El upsert de personal_scripts ya no sobreescribe enabled en la rama UPDATE: la flag puesta por el operador es sticky a través de nexo scripts sync. Cuatro tests nuevos en tests/test_personal_scripts_enabled.py cubren round-trip, error envelope, status shape y la regresión del sticky flag.
Una nueva tabla email_accounts (migración m46) permite que un mismo NEXO Brain gestione varias cuentas de correo a la vez, cada una con sus coordenadas IMAP / SMTP, rol (inbox/outbox/both), email del operador y dominios de confianza. Las contraseñas no se guardan en esta tabla — sólo un puntero (credential_service+credential_key) a la credentials table existente, igual que cualquier otro secreto del runtime. nexo email setup es un wizard interactivo (preguntas guiadas, getpass, prueba IMAP+SMTP en el mismo flujo). nexo email add --label X --email X --imap-host X --password-stdin --json es la variante no-interactiva: la contraseña se lee desde stdin para que nunca aparezca en argv ni en ps. list / test / remove aceptan --json para consumidores máquina. La release coordinada de NEXO Desktop (v0.19.0) usa este contrato JSON para ofrecer un panel Settings → Email que listo, añado, prueba y elimina cuentas con un formulario modal — los operadores no técnicos ya no editan ningún fichero de configuración. Un migrador idempotente (auto_update.py) promociona el legacy ~/.nexo/nexo-email/config.json en la siguiente sesión; los operadores existentes no necesitan hacer nada.
El auditor Opus 4.7 xhigh nocturno detectó que src/presets/entities_universal.json en v6.3.0 subía al paquete público entradas vhost_mapping específicas del operador (IPs privadas, hostnames de tenants, docroots). v6.3.1 saca esas entradas a src/presets/entities_local.sample.json (plantilla) + ~/.nexo/brain/presets/entities_local.json (copia local del operador, .gitignore'd). El installer nexo init escribe la plantilla en la primera instalación y nunca pisa la copia del operador. Comportamiento del Guardian sin cambios.
Coordinated with NEXO Desktop v0.18.0. Extends the cognitive_sentiment shape with is_correction, valence and intent enum. Amplia el schema de entities con aliases, metadata, source, confidence y access_mode vía la migración idempotente m44. Aterriza 21 fixtures etiquetadas con spike gates de R13 (FP < 5%, P95 < 3s). Bucles Fáse F (src/fase_f_loops.py + phase_guardian_analysis.py) alimentan Deep Sleep con métricas por regla, agrupación de falsos positivos y candidatos de falso negativo para nuevas reglas en sombra. Esqueleto del classifier local zero-shot con pin exacto de MoritzLaurer/mDeBERTa-v3-base-mnli-xnli y su política de upgrade documentada. El hook de strict mode respeta NEXO_MIGRATING=1, columna origin en personal_scripts, y el gate T4 envuelve R15 / R23e / R23f / R23h con paridad Py ↔ JS. Dos auditores pre-release detectaron un wire JS dead-code (CRITICAL) y una ambigüedad del classifier (HIGH); ambos corregidos con regression tests antes del merge.
Coordinated with NEXO Desktop v0.17.0. Primer release vía el plan de dos olas. Introduce R26–R34 en el system prompt, R-CATALOG (0.X.2) como gate pre-*_create, la sección locations en nexo_system_catalog, T5 R34 identity coherence con paridad CLAUDE.md / AGENTS.md, T0/T1/T2/T3 deuda Desktop, Fase B cerrada 12/12 con tests unitarios y el bug modal bullets corregido.
Small follow-up to v6.1.0. The Brain auto-update banner in NEXO Desktop depends on parsing Latest: vX from nexo --help. Prior gate at _should_refresh_latest_version() used isatty() to decide whether to hit npm — this excluded Desktop’s subprocess (stdio piped). v6.1.1 drops the TTY gate; the 6-hour cache max-age is the real rate-limit. Fail-closed to installed-only when npm unreachable.
Protocol Enforcer Fase 2 ships. Capa 2 runtime guardian with 25 rules (R13–R25 + R23b–R23m) keeping Claude Code / Codex / NEXO Desktop aligned to protocol. Core rules (R13 pre-Edit guard, R14 post-correction learning, R16 declared-done, R25 Nora/María read-only) ship with defence-in-depth: guardian.json cannot turn them off. Incident-driven D2 covers git push --force to main/master, DELETE/UPDATE without WHERE, scp to the wrong docroot, chown -R on root-ish paths, secrets echoed into output streams, duplicate outbound messages, shebang-vs-interpreter mismatch (no shell injection), and more. Templates byte-for-byte parity across src/enforcement_engine.py and the NEXO Desktop JS twin.
Migration v43 session_claude_aliases — 1-to-N map from NEXO sid to every Claude session UUID. Fixes the NEXO Desktop multi-conversation block where every second conversation’s PreToolUse hook failed with “unknown target”. _resolve_nexo_sid now consults aliases first, falls back to legacy column (pre-v43 rows), then to the v6.0.7 single-active fallback.
Audit cycle applied. External-LLM audit + Opus 4.7 effort-high self-audit. Log redaction now covers Bearer/sk-/pk-/api_key/JWT/AWS/GitHub/Shopify/KEY=VALUE/mysql -p<pass>. R23f heredoc multiline, R23h native PATH resolution, R14 detector awaited, hermetic map lookup, cross-engine parity harness in strict mode, red-team suite (32 attempts across 12 rules). Guardian telemetry NDJSON + scripts/install_guardian.py installer + docs/guardian-quickstart.md operator guide.
Suite: 291 pass + 2 skip documented. Paired with NEXO Desktop v0.15.0 (Fase 2 JS twins, Guardian Proposals panel, Brain auto-update install flow with combined “Actualizar todo” banner).
$NEXO_HOME/bin into the developer’s shell profileAny pytest run with NEXO_HOME=/tmp/pytest-xxx used to append export PATH="/tmp/pytest-xxx/bin:$PATH" to the real ~/.bash_profile, ~/.bashrc, and ~/.zshrc. v6.0.6 gates the write at all three installer sites.
src/auto_update.py::_ensure_runtime_cli_in_shell()) and the two JavaScript sites in bin/nexo-brain.js (install Step 8 + migration restore) computed the rc file list from Path.home() / os.homedir() regardless of where NEXO_HOME pointed. The check was asymmetric: write target came from the real $HOME, but the export PATH value came from NEXO_HOME._should_skip_shell_profile_backfill() returns (skip, reason) based on (a) NEXO_SKIP_SHELL_PROFILE=1|true|yes|on and (b) whether NEXO_HOME resolves to managed_nexo_home(). Consulted by _ensure_runtime_cli_in_shell() before touching any rc file.shouldSkipShellProfileBackfill() in bin/nexo-brain.js gates the install Step 8 alias + PATH block and the migration restore block.NEXO_SKIP_SHELL_PROFILE=1 force-skips the backfill even when NEXO_HOME is canonical — useful for sandboxed test runners, container smoke tests, or installs where the host shell must remain untouched.tests/test_auto_update_shell_profile.py with 5 regression cases: pytest tmp dir, env flag on, canonical install, all truthy flag values, canonical install with NEXO_SKIP_SHELL_PROFILE=0..github/workflows/tests 2.yml (accidentally committed with v6.0.5) and purged 78+ stale __pycache__/*\ 2.* Finder-copy artefacts.Fix for the block storm several Claude Code versions caused in 6.0.2–6.0.4, plus the CI gate that would have caught it.
src/hook_guardrails.py::process_pre_tool_event only consulted payload["session_id"]. Several Claude Code builds deliver PreToolUse without that field, so the strict branch recorded a strict_protocol_write_without_startup debt and the formatter emitted “NEXO STRICT MODE BLOCKED THIS EDIT — Start the shared-brain session first” even when the operator already had nexo_startup + nexo_task_open + nexo_guard_check + nexo_track in the session. Tracked as learning #411.process_pre_tool_event now walks payload → $NEXO_HOME/coordination/.claude-session-id → empty. The SessionStart hook already writes that file on every session, so the fallback works without extra configuration for all users. Fail-closed is preserved: if neither the payload nor the file yields an id the guardrail still blocks with missing_startup.ruff, bandit, verify_release_readiness, and verify_client_parity — never pytest. v6.0.5 adds .github/workflows/tests.yml which runs pytest tests/ -q --maxfail=5 on every PR and push to main, blocking merges on failure.test_process_pre_tool_event_allows_public_contribution_checkout, test_process_pre_tool_event_does_not_treat_runtime_home_as_live_repo_when_not_git_checkout (both asserted a skipped/lenient shape that no longer applies — public contribution still runs strict, only the live-repo guard is relaxed), and test_non_tty_returns_lenient (leaked NEXO_INTERACTIVE=1 from the parent shell; _force_tty now monkeypatch.delenvs it).tests/test_protocol.py cases that assert a stale handle_task_close shape are pytest.mark.xfail(strict=False) pending the refactor tracked as NF-TEST-PROTOCOL-API-REFACTOR.default_resonance
Closes the last gap left by the v5.9.0 resonance-map rollout. nexo chat (build_interactive_client_command) and the NEXO dashboard's "Open followup in Terminal" action (build_followup_terminal_shell_command) were building the claude / codex command straight from client_runtime_profiles in config/schedule.json, ignoring preferences.default_resonance. Users who switched their Resonance in NEXO Desktop Preferences (Alto → writes brain/calibration.json) kept getting the stale tier cached in the legacy profile — typically max. Headless runs (run_automation_prompt) and NEXO Desktop new-sessions already honoured the preference correctly; only the two terminal launchers were stuck. Fix: a new _resolve_interactive_model_and_effort(caller, backend, ...) helper in src/agent_runner.py consults resonance_map.resolve_model_and_effort first and falls back to client_runtime_profiles only when the resonance contract is missing. Both builders now use it; build_interactive_client_command accepts caller= (default nexo_chat) and tier= overrides that run_automation_interactive propagates through. Registry: nexo_followup_terminal joins USER_FACING_CALLERS with the user-default sentinel so the dashboard launcher resolves against the user's preference. Tests: 8 existing pytest cases updated across test_agent_runner.py, test_cli_scripts.py, and test_resonance_map.py; full suite stays green.
guard_checks.session_id Fix
Double-fix release. Fix 1: resonance_tiers.json is now published to the public contract path ~/.nexo/brain/resonance_tiers.json that NEXO Desktop ≥ 0.12.0 reads on startup. Pre-v6.0.3 the installer kept writing it to the legacy location ~/.nexo/resonance_tiers.json, so Desktop failed to start Claude with "NEXO Brain contract missing" on every fresh install and every update from 6.0.0 / 6.0.1 / 6.0.2 unless the user copied the file by hand. The Brain's own Python runtime never saw the symptom because it read the file from __file__.parent. Fix layered across three files: new publishBrainContracts(srcDir, nexoHome) helper in bin/nexo-brain.js (writes to brain/ and unlinks the legacy copy on every install and update); three-step resolution walk in src/resonance_map.py (NEXO_HOME/brain/ → legacy NEXO_HOME/ → src/, honours $NEXO_HOME); idempotent _relocate_resonance_tiers_contract(dest) migration in src/auto_update.py that promotes legacy runtimes on nexo update and unlinks the old copy. Fix 2: nexo_guard_check now writes the caller's SID into guard_checks.session_id instead of the empty string v6.0.2 hardcoded. Resolution walks NEXO_SID env → CLAUDE_SESSION_ID env translated via sessions.external_session_id → most-recently-updated sessions row. The empty string is only written when sessions is literally empty, which is the right "nothing to guard" signal. hook_guardrails._session_has_guard_check can finally match the call to the current session, so strict-protocol sessions stop tripping "no guard_check seen for this session" after every successful call. Tests: 5 new cases in test_auto_update_relocate_resonance.py (relocation, cleanup, idempotency, absence no-op, exception safety); 4 new cases in test_guard.py (env resolution, external_session_id translation, most-recent-session fallback, empty-sessions edge). Full suite stays green.
personal/ Caller Prefix + tier Kwarg + Personal Scripts Guide
v6.0.0 made caller mandatory on run_automation_prompt and resolved it against USER_FACING_CALLERS / SYSTEM_OWNED_CALLERS in src/resonance_map.py. That was exactly right for callers inside the repo — each one deserves a deliberate, reviewable tier. But it was impossible for scripts that live in the operator's ~/.nexo/scripts/ tree: they cannot edit the public repo, and every one of them collapsed to the generic agent_run/generic fallback, erasing per-script identity. v6.0.2 introduces the reserved caller prefix personal/. The resolver bypasses the registry for any caller whose id starts with it and follows a deterministic precedence chain: explicit tier= → explicit reasoning_effort= → calibration.preferences.default_resonance → DEFAULT_RESONANCE ("alto"). Invalid tier values are silently ignored rather than raising, so a typo falls through to the next step instead of breaking the caller. Added: new kwarg tier: str = "" on run_automation_prompt, run_automation_interactive, nexo_helper.run_automation_text, nexo_helper.run_automation_json; new CLI flags --tier and --caller on nexo-agent-run.py; new doc docs/personal-scripts-guide.md so any NEXO session helping an operator author a personal script knows the exact pattern. Changed: resolve_tier_for_caller and resolve_model_and_effort accept a new keyword-only argument explicit_tier; README gains a link to the new guide. Backcompat: callers registered in either dictionary keep v6.0.0 behaviour untouched; non-personal/ ids without a registry entry still raise UnregisteredCallerError. Tests: 3 new pytest modules, 14 new cases. Full suite: 1079 passed, 1 skipped.
NEXO_INTERACTIVE Override + PostToolUse Inbox Autodetect
Two hotfixes on top of 6.0.0. Fix 1: protocol_settings.py used to classify the process as interactive only when sys.stdin.isatty() and sys.stdout.isatty() — but NEXO Desktop 0.12.0 spawns claude through pipes, so both sides report False even with a human in the loop and v6.0.0 fell back to lenient. The detector now also treats the process as interactive when NEXO_INTERACTIVE is exactly the string "1". Truthy-looking aliases (true/yes/on/1 / 1) are deliberately rejected so a typo cannot silently strict-mode a headless cron. NEXO_INTERACTIVE is an internal contract between Brain and interactive clients — not user-facing, not documented to operators, not a resurrection of the removed NEXO_PROTOCOL_STRICTNESS. Fix 2: autopilot Claude Code sessions (long streams of tool calls with no user turns) could not see inbound nexo_send messages until the user intervened manually because nexo_heartbeat only fires on user messages. v6.0.1 adds an inbox-autodetect stage at the end of the PostToolUse hook: when the session has unread messages AND the last heartbeat is more than 60s old (configurable via NEXO_INBOX_CHECK_THRESHOLD_SECONDS), the hook emits a systemMessage telling the agent to run nexo_heartbeat and consume the inbox. Rate-limited to one reminder per minute per SID via the new hook_inbox_reminders table. Added: sessions.last_heartbeat_ts column stamped by every successful heartbeat; helpers update_last_heartbeat_ts, get_last_heartbeat_ts, count_pending_inbox_messages, resolve_sid_from_external, get_last_reminder_ts, mark_reminder_sent, reset_reminders_for_sid. Idempotent migration m42. 6 new pytest modules (test_protocol_strictness_nexo_interactive.py, test_inbox_autodetect.py, test_inbox_reminder_rate_limit.py, test_heartbeat_updates_last_ts.py, test_v6_0_1_migration.py, test_inbox_autodetect_e2e.py); full suite 1065 passed, 1 skipped.
auto_capture Wired to Live Events
BREAKING. Onboarding asks one resonance tier (maximo/alto/medio/bajo) instead of per-backend model + effort; src/resonance_tiers.json becomes the single source of truth that src/resonance_map.py consumes via the new load_resonance_table(). Legacy client_runtime_profiles.{claude_code,codex}.{model,reasoning_effort} are purged from schedule.json on upgrade. Protocol strictness is no longer configurable: interactive TTY runs strict, non-TTY (crons, pipes, tests) runs lenient; NEXO_PROTOCOL_STRICTNESS env, preferences.protocol_strictness, and the default/normal/off/warn/soft aliases are all removed. preferences.show_pending_at_start moves to NEXO Desktop electron-store. The seven core hooks are unified behind src/hooks/manifest.json — both plugin mode (hooks/hooks.json) and npm mode (bin/nexo-brain.js registerAllCoreHooks()) register from the same file, and registerAllCoreHooks() prunes v5.x legacy shell hook entries while leaving user-custom hooks alone. Two new hooks ship: Notification records live-session activity via hook_observability.record_activity() so auto_close_sessions stops pruning busy sessions, and SubagentStop auto-closes protocol_tasks that a subagent opened without calling nexo_task_close. auto_capture.py is wired to both UserPromptSubmit and PostToolUse, with a persistent 1h dedup table (auto_capture_dedup) and an automatic nexo_learning_add on correction matches (category auto, priority medium). ~/.nexo/hooks_status.json is published after every registerAllCoreHooks() run so NEXO Desktop ≥0.12.0 can render Hooks activos X/Y. New nexo-brain --skip flag aliases --yes/--defaults; interactive defaults for Deep scan, Caffeinate (macOS), and the Dashboard now answer yes on bare ENTER. Empty name prompt falls through to "Usuario". calibration_migration.apply_v6_purge() runs exactly once from auto_update._run_runtime_post_sync(), seeds preferences.default_resonance="alto" only when missing and never overwrites an existing value. 7 new pytests cover the loader, migration, auto_capture dedup + learning, TTY strictness, hooks_status.json publish, manifest/plugin parity, and the --skip fresh-install smoke. Full suite: 1057 passed, 1 skipped.
brain/profile.json From Calibration + Desktop Explains Each Block
NEXO Desktop's Preferencias → Avanzado tab renders two JSON blocks: calibration.json (editable personality/language/name) and profile.json (deep-scan from onboarding). Operators whose onboarding was interrupted before v5.9.x ended up with role and technical_level only under calibration.meta.* and no profile.json file — the Desktop block rendered an empty {} with no context, which looked broken. v5.10.2 closes the gap from both ends. Brain: new _bootstrap_profile_from_calibration_meta(dest) runs inside _run_runtime_post_sync() right after the v5.10.1 effort→resonance migration. When profile.json is missing / empty / corrupt and calibration.json carries any of meta.role, meta.technical_level, name, language, it seeds the profile with those fields plus a source marker. Never overwrites a populated profile, never raises, idempotent. Desktop v0.11.2: the Avanzado tab now prefixes each block with a short explanation of what lives where, and renders a friendly placeholder instead of {} when no profile exists yet. Also fixes test_user_facing_caller_with_no_user_default_uses_alto which was leaking real ~/.nexo state after the v5.10.1 migration wrote default_resonance=maximo on the dev box. 10 new tests (test_auto_update_bootstrap_profile.py); full suite 1021 passed, 1 skipped.
reasoning_effort=max → preferences.default_resonance
v5.9.0 introduced the resonance map (maximo/alto/medio/bajo) and v5.10.0 made it prevail over the legacy client_runtime_profiles.claude_code.reasoning_effort hint. That removed a subtle double-writer bug, but it also meant any operator whose only recorded preference was the legacy reasoning_effort="max" silently fell back to DEFAULT_RESONANCE="alto" on the first interactive call after the update — effectively a one-tier downgrade. NEXO Desktop's header on a fresh conversation would show POTENCIA: ALTO even when the operator had configured max long before. v5.10.1 adds a one-shot, conservative, non-destructive migration inside _run_runtime_post_sync(): reads config/schedule.json, if brain/calibration.json does not already declare preferences.default_resonance, writes the equivalent tier (max→maximo, xhigh→alto, high→medio, medium→bajo). No-op when either location already has an explicit default_resonance; unknown/unsupported efforts skipped; corrupt calibration.json rewritten safely; errors swallowed into resonance-migration-warning:* action lines. Idempotent by construction. 10 new tests (test_auto_update_migrate_effort.py) plus a test-harness fix that unblocks test_cron_recovery.py against main (missing model_defaults, resonance_map, db, etc. in the copied runtime tree since v5.9.x). Full suite: 1011 passed, 1 skipped.
Deep-sleep Session 1 took ~57 min on some installs because every claude -p child reloaded ~/.claude/CLAUDE.md (11 KB), hook sync, plugin refresh, keychain probe. New bare_mode kwarg on run_automation_prompt wires claude --bare for JSON-only callers: deep-sleep/extract and deep-sleep/synthesize auto-enable it when an ANTHROPIC_API_KEY is resolvable (env → ~/.claude/anthropic-api-key.txt → ~/.nexo/config/anthropic-api-key.txt; silent fallback when no key). ~4.3× faster per child on the reference install. caller= is now mandatory — run_automation_prompt raises UnregisteredCallerError without a registered caller. Five personal scripts (personal/email-monitor, personal/github-monitor, personal/post-x, personal/followup-runner at alto, personal/orchestrator-v2 at maximo) joined SYSTEM_OWNED_CALLERS. gbp/* marketing callers bumped medio → alto (public-facing copy, quality first). 65 legacy protocol debts bulk-resolved — patterns structurally closed by mandatory caller= + unified log + bare_mode. 10 new bare-mode tests (974 total in suite).
v5.9.0 shipped the four resonance tiers and the nexo preferences --resonance CLI. v5.9.1 surfaces the same control inside NEXO Desktop's existing Preferences dialog without requiring a Desktop release — Desktop already fetches its editable fields via nexo schema --json, so declaring preferences.default_resonance in src/desktop_bridge.py makes the selector appear automatically (four localised options, inline hint reminding that crons stay pinned per caller). New _load_user_default_resonance() reads brain/calibration.json first (where Desktop writes) and falls back to config/schedule.json (where the v5.9.0 CLI wrote). resolve_tier_for_caller calls it automatically when user_default is not passed, so nexo chat picks up Desktop's edit without changes. nexo preferences --resonance writes to both locations to keep them in sync. 6 new tests (20 total in resonance_map suite).
Every Claude/Codex invocation now flows through a central resonance map in src/resonance_map.py: four tiers (MAXIMO / ALTO / MEDIO / BAJO) each resolve to a concrete (model, reasoning_effort) pair per backend. User-facing callers (nexo chat, Desktop new conversation, interactive nexo update) honour the user's default_resonance; system-owned callers are pinned per caller — deep-sleep/synthesize and evolution/run run MAXIMO, gbp/* marketing posts run MEDIO. Unknown callers raise UnregisteredCallerError. Migration #41 adds caller, session_type, started_at, ended_at, pid, resonance_tier to automation_runs; interactive sessions record a row at spawn with ended_at=NULL and update it on close. New run_automation_interactive() covers nexo chat; new MCP tools nexo_session_log_create / nexo_session_log_close let NEXO Desktop (which spawns claude directly) feed the same log. New nexo preferences --resonance CLI writes default_resonance into schedule.json. 20 new tests.
v5.8.0 shipped an auto-classifier in src/db/_classification.py that fired whenever agents omitted internal or owner on nexo_followup_create / nexo_reminder_create. It matched NEXO-specific ID prefixes (NF-PROTOCOL-*, NF-DS-*, NF-AUDIT-*), Spanish user-verbs (debes, revisar, firmar), and agent keywords (monitor, auditoría diaria, checkpoint). 5.8.2 removes it entirely: the Brain core now persists internal=0 and owner=NULL when callers omit them, and clients that want automatic classification (NEXO Desktop does, via _legacyClassifyOwner/_legacyIsInternalTaskId) compute it themselves. Migration #40 keeps the columns + indexes; previously backfilled rows keep their values. normalise_owner still explicitly rejects the string "nexo" so legacy hardcoding cannot sneak back in. Test suite rewritten around the neutral contract (12 cases).
Between 2026-04-14 and 2026-04-17 the nightly deep-sleep on the reference install stopped producing artifacts. Root cause was a feedback loop: the wrapper only wrote cron_runs at end, the watchdog used cron_runs as its source of truth for “stuck”, and launchctl kickstart -k killed the running worker every 30 min. 5.8.1 fixes it at the source — two-phase cron_runs recording (INSERT at start with ended_at=NULL, UPDATE at end) with SIGTERM/INT/HUP trap that still closes the row; watchdog in-flight detection that never kickstart -ks a running worker; extractor failure classification that separates transient (overloaded_error, rate-limit, timeout, signal — retried next run) from deterministic (skipped after MAX_POISON_ATTEMPTS); slim shared-context (200 head lines + metadata instead of 400+ KB full dump); and an idempotent auto_update._heal_deep_sleep_runtime() that repairs existing installs silently on the next nexo update.
Task classification moves from client-side regex into persistent storage every MCP client shares. Migration #40 adds internal and owner columns on followups and reminders, with an idempotent one-shot backfill. Taxonomy is owner in {user, waiting, agent, shared} — agent is deliberately generic so third-party deployments render their own assistant label instead of hardcoding “NEXO”. nexo_reminder_create, nexo_reminder_update, nexo_followup_create, and nexo_followup_update gain optional internal and owner parameters. Closes a UX paradox where tasks labelled “Para ti” could be hidden by the “Tareas internas” filter in NEXO Desktop.
nexo update now keeps your terminal CLIs in lockstep with NEXO Brain itself. When the global @anthropic-ai/claude-code or @openai/codex packages are installed, the updater checks the npm registry and runs npm install -g <pkg>@latest in-line before the post-update verify step. Packages that were never installed globally are skipped silently. Pass nexo update --no-clis (or include_clis=False on the MCP tool) to pin them manually.
Two small-but-sharp fixes in nexo update. 0-byte .db orphans from interrupted installs are now purged from ~/.nexo/ and ~/.nexo/data/ before the pre-update backup runs, so backup validation no longer trips over empty shells. And when heal_runtime_profiles() migrates the claude_code default, the new sync_claude_code_model() helper also updates the model field in ~/.claude/settings.json — the file Claude Code actually reads — so the boot model matches NEXO’s recommendation on the next launch.
NEXO Brain now ships with Claude Opus 4.7 and reasoning_effort: "max" — the highest reasoning tier available. Auto-migration on nexo update silently upgrades existing users from claude-opus-4-6* to claude-opus-4-7, preserving the 1M context suffix. Codex profiles (GPT-5.4 / xhigh) are untouched.
Same-day follow-up to v5.5.5. nexo_backup_now, nexo_backup_restore, and export_user_bundle now refuse reentrant calls inside 30 s / 60 s / 120 s windows. A runaway MCP client stuck in a tool-use loop can no longer hammer sqlite3.Connection.backup(). v5.5.5 neutralised the consequences of the 2026-04-16 incident; v5.5.6 closes the cause.
A hotfix for the 2026-04-16 incident where one user's ~/.nexo/data/nexo.db was reset to a 4 KB empty-schema file while three consecutive nexo update attempts each captured the already-empty DB into a new pre-update-* snapshot, masking the wipe. v5.5.5 adds a pre-flight wipe guard, validated sqlite3.backup copies, a post-migration row-count gate, and a startup self-heal that auto-restores from the newest hourly backup on boot when a wipe is detected. New nexo recover CLI + nexo_recover MCP tool.
Phase 2 extraction was retrying the same session three times with identical prompt and context, hiding a 6h per-attempt safety net that had silently drifted out of alignment with its own "3h" comment. Retries dropped from 3 to 2, the JSON system prompt gained an escape hatch so the model always returns parseable output, and all 10 automation subprocess timeouts now live in a single AUTOMATION_SUBPROCESS_TIMEOUT constant in src/constants.py.
Aligned models (Opus 4.6, safety-tuned variants) stopped rejecting heartbeat, diary, and checkpoint injections as suspected prompt injection. A new CORE section teaches the model that <system-reminder> messages prefixed with [NEXO Protocol Enforcer] are legitimate protocol instructions. Paired with NEXO Desktop v0.9.25 which wraps every enforcer prompt accordingly.
ensure_personal_schedules now verifies launchctl loaded state and auto-repairs unloaded agents on startup. Core automation scripts also stop hardcoding legacy opus/sonnet fallbacks and now defer empty model selection to the configured runtime profile.
Fixed silent import failure when headless sessions run from non-NEXO directories. Added comprehensive logging to enforcer-headless.log and dedup logic (skips injection if tool was called <60s ago).
Headless sessions (Deep Sleep, email-monitor, followup-runner, etc.) now use stream-json mode with Popen instead of one-shot -p. Real-time monitoring of tool calls with enforcement injection via stdin when protocol rules are violated.
All headless sessions (Deep Sleep, email-monitor, followup-runner, catchup, synthesis, evolution, etc.) now receive enforcement rules automatically via append_system_prompt in run_automation_prompt(). Single integration point covers ~15 scripts without modifying any of them.
Complete rewrite of tool-enforcement-map.json with multi-dimensional enforcement rules based on actual source code analysis. New levels: must (inject prompt), should (remind), may (track), none (on-demand). Each tool declares dependencies, chain triggers, internal sub-calls, and conditional rules. 11 must + 10 should + 1 may + 225 none = 247 tools mapped.
Canonical map of all 247 NEXO Brain MCP tools with enforcement metadata. NEXO Desktop and headless session-guard read this map to mechanically enforce protocol compliance. Includes verify_tool_map.py for drift detection.
nexo update now manages external runtime dependencies declared in package.json runtimeDependencies. First dependency: @anthropic-ai/claude-code — checks version, installs if missing, updates if outdated. New daily auto-update cron at 02:00 runs the full update flow automatically. The system is declarative: adding future dependencies is a single line in package.json.
Increased test_update_uses_recorded_source_repo subprocess timeout from 10s to 30s. The full nexo update --json flow exceeds 10 seconds on GitHub Actions runners even with a fake venv.
Completes the publish workflow fix: v5.4.3 added missing tree_hygiene.py copies, v5.4.4 adds fake .venv directories so _ensure_runtime_venv does not try to create a real venv during tests (which timed out on GitHub Actions runners).
Hotfix: 2 tests in TestRuntimeUpdate that broke the v5.4.2 publish workflow now correctly copy tree_hygiene.py into their isolated runtime directories, resolving the ModuleNotFoundError that prevented the CI publish job from completing.
A low-level integrity patch: release warnings now distinguish repo git debt from local/runtime operations, the nocturnal postmortem drains pending session_buffer.jsonl events instead of looking only at "today", and docs now describe the real stop-hook / reflection boundary honestly.
commit_ref warnings now count repo-tracked changes only. Local/runtime/server-side operations can be linked explicitly without pretending they should have a repo hash.session_buffer.jsonl as a real pending queue, ingests useful hook/tool events, and prunes only the lines that were actually consumed.See the full release post.
A post-mortem first and a patch second. The PostToolUse capture-session.sh hook had been reading a nonexistent env var since its introduction, polluting the Sensory Register with 100% noise. This release fixes the hook, removes a runtime-only duplicate, and purges pre-fix entries from the buffer on update.
$CLAUDE_TOOL_NAME — an environment variable Claude Code has never set. Tool name arrives in a JSON payload on stdin. A later "hardening" commit absorbed stdin but never parsed it, entrenching the bug behind a plausible-looking defensive change.tool_name from stdin JSON with python3 (same pattern capture-tool-logs.sh already used). Empty tool name exits silently instead of writing noise. Bash is no longer filtered — it is where commits, pushes, and npm publishes live.~/.nexo/hooks/capture-session 2.sh duplicate deleted. v5.3.29 gates block these in the repo tree but not in the runtime bucket; v5.4.1 supersedes both copies.nexo update strips pre-existing "tool":"unknown" lines from session_buffer.jsonl, keeps a .pre-v5.4.1.bak backup, runs once per host.See the full post-mortem.
nexo notify / health / logs + calibration migration
External UIs stop polling and start reacting. NEXO Brain now exposes a stable runtime event stream, a subsystem health snapshot, structured log tailing, and a safe silent migration for older calibration.json files.
~/.nexo/runtime/events.ndjson, monotonic id, stable envelope, 5 MB rotation, fcntl-locked writes. Event types: attention_required, proactive_message, followup_alert, health_alert, info.nexo notify TYPE --text ... --reason ... --priority low|normal|high|urgent — one-shot emitter for recovery scripts, followup runners, and health watchers.nexo health --json — rolled up status: ok|degraded|error across runtime, database, crons, MCP wiring, recent errors, and the event bus.nexo logs --tail [--lines N] [--source all|events|operations|<file>] [--json] — single entry point for Desktop to read logs without opening a terminal.nexo doctor --migrate-calibration [--calibration-dry-run] plus implicit migration inside nexo update: calibration.json moves from flat to nested with a pre-migrate backup. Reverts on failure. No-op if already nested.Pure additive surface. See the release post.
External UIs like NEXO Desktop can now render preferences, identity, onboarding, and profile heuristics from live JSON instead of hardcoding fields and releasing in lockstep with the runtime.
nexo schema --json — editable-field schema with schema_version, groups, multilang labels, and select options. Desktop renders Preferences tabs from this payload.nexo identity --json — canonical {name, source, writable_source}. One probe, one canonical write path.nexo onboard --json — stepwise wizard with prompt, type, writes, file, default, optional, validate.nexo scan-profile — idempotent profile builder from CLAUDE.md + calibration.json. Preview by default; --apply writes, --force overwrites.Pure additive surface. No existing commands touched. See the release post.
Block 1 of the technical audit closes as a real public release: duplicate artifacts stop hiding in local trees, packaged/runtime updates converge on one canonical core, corrupt DB state no longer respawns an empty brain by default, and cron evidence survives transient SQLite failure instead of vanishing quietly.
.gitignore no longer hides * 2 copies, loaders skip them explicitly, and both preflight and release-readiness fail if they reappear. Local contamination stops pretending to be harmless noise.
src/scripts/nexo-update.sh now delegates to the canonical Python handler instead of carrying a parallel shell implementation. Packaged/runtime updates stop drifting depending on which entry point ran.
Server preflight now runs synchronously, and corrupt SQLite state no longer spawns a fresh empty brain by default. Recovery requires explicit operator intent via NEXO_ALLOW_FRESH_DB_ON_CORRUPTION=1.
The cron wrapper now writes a complete row after command exit and spools JSON under ~/.nexo/operations/cron-spool if SQLite is unavailable. Execution traces stop disappearing into null-ended rows.
verify_release_readiness.py now verifies the repo-facing public copy as well: README.md, llms.txt, index.html, blog/index.html, changelog/index.html, and sitemap.xml. A tag is no longer “ready” if the outward-facing story still describes an older version.
A subtle protocol loophole is gone: calling nexo_guard_check once early in the session no longer satisfies the contract for every later file edit.
process_pre_tool_event verifies that the guarded file matches the edit target, so conditioned learnings stop being bypassable by one stale check earlier in the session.
Instead of silently accepting the mismatch, the runtime now records explicit debt when a write happens without the corresponding per-file guard evidence.
Long sessions and delayed closeouts stop guessing the calendar. Every heartbeat now begins with an authoritative UTC timestamp that clients can format locally.
nexo_heartbeat now emits NOW_UTC, so “ayer”, “mañana”, and day-of-week phrasing stop drifting during long-running tasks and email work.
The core remains neutral: UTC is authoritative, while formatting stays in the operator/runtime layer instead of hardcoding locale or timezone into product logic.
model_defaults.json
The single-source model-defaults architecture from v5.3.24 was correct in the repo but incomplete in the packaged runtime path until the JSON itself was copied into ~/.nexo.
The installer/runtime sync now copies model_defaults.json into NEXO_HOME, so future recommendation bumps propagate without depending on hardcoded Python fallbacks.
Without the JSON in the runtime, packaged users could stay on stale defaults even though the repo and npm package had already moved forward. That delivery gap is now closed.
The permissions allowlist from v5.3.24 was necessary but not sufficient: headless claude -p still needed the explicit bypass flag or cron automation would wait forever for approvals nobody could grant.
agent_runner.run_automation_prompt now passes the permissions-bypass flag on every headless Claude invocation, so followup-runner, email-monitor, and Deep Sleep stop zombifying on approval prompts.
The fix applies only to non-interactive automation. Daily interactive work keeps the normal approval flow and operator control.
Three compounding bugs shared one root cause: NEXO had no single source of truth for model defaults. Python runtime, JS installer, and client-config sync each kept their own copy and silently drifted. v5.3.24 consolidates everything into src/model_defaults.json, read identically by both runtimes, with a one-time upgrade prompt when a maintainer ships a new recommendation.
src/model_defaults.json defines Claude Code + Codex defaults (model, reasoning effort, display name, recommendation version, previous defaults). Both Python and the JS installer read the same file, so drift is impossible.
The historical DEFAULT_CODEX_MODEL = DEFAULT_CLAUDE_CODE_MODEL alias is gone. Codex default is gpt-5.4 / xhigh. Client sync refuses to write Claude-family models into ~/.codex/config.toml, and existing bad writes are healed on the next nexo update.
Fresh installs now write a minimum permissions.allow list into ~/.claude/settings.json (Bash, Read, Edit, Write, Glob, Grep, Task, Skill, NotebookEdit, WebSearch, WebFetch, mcp__*) so headless automation stops stalling on approval prompts. Codex gets approval_policy = "never" and sandbox_mode = "danger-full-access" as defaults.
Bumping recommendation_version in the JSON triggers a single interactive prompt on the user's next nexo update — only if they are still on a prior NEXO default. Customized models are respected silently. Users already on the current recommendation are auto-acknowledged without any output.
nexo update no longer crashes on slow reposIf the runtime was ever synced from a local checkout, git status --porcelain timing out now returns a graceful error instead of an unhandled TimeoutExpired that crashed every nexo update.
Model-profile heal now runs on both the legacy sync flow (auto_update.py::manual_sync_update) and the packaged npm update flow (plugins/update.py) so stale claude-* values in schedule.json are cleaned regardless of install method.
5.3.10 closed quiet truth gaps in packaged runtime metadata, deep doctor, Evolution telemetry, and synthesis. The next issue that surfaced was more subtle: several protocol/Cortex surfaces still accepted malformed structured parameters and silently rewrote them into different valid states. 5.3.11 closes that trust leak directly.
nexo_task_close now rejects invalid outcome values explicitly instead of silently coercing them to failed. Bad payloads no longer poison protocol history, debt, or hot-context summaries with failures that never really happened.
nexo_task_open and nexo_confidence_check now reject invalid task_type values instead of quietly degrading them to another valid type. The runtime now says the contract is wrong instead of guessing what the caller meant.
nexo_cortex_check and nexo_cortex_decide now reject malformed task_type, and Cortex decisions also reject malformed impact_level instead of silently promoting it to high. Decision weighting stays faithful to the actual request.
The DB helpers behind protocol and Cortex now validate the same canonical values before writing rows. Malformed internal calls can no longer sneak bad semantics into persisted task, debt, context, or evaluation data.
The 5.3.7 through 5.3.9 release line fixed real packaged-runtime breakages on real machines, but some quieter trust gaps remained: runtime metadata could still drift, deep doctor could look degraded before the first self-audit artifact existed, weekly Evolution could finish without persisting any score telemetry, and startup/update summaries were still being written without re-entering the shared-brain loop. 5.3.10 closes those gaps together.
Fresh installs, migrations, and same-version refreshes now copy the published root package.json into ~/.nexo. Version metadata inside the live runtime stops drifting behind the actual npm package that just finished installing.
If the daily self-audit is configured but the runtime was just installed or updated, deep doctor now reports that the summary is still pending instead of degrading the whole check because self-audit-summary.json does not exist yet.
The weekly Evolution prompt now explicitly requires canonical dimension_scores and score_evidence. That restores the intended telemetry path into evolution_metrics, and the status surface falls back to the objective file if rows are still missing.
update-last-summary.json now feeds daily synthesis only when it contains something operationally important such as deferred syncs, bootstrap changes, schedule healing, notices, or errors. Routine cooldown/no-op summaries stay silent instead of polluting the briefing.
Real-machine validation of 5.3.8 exposed a more serious packaged regression: the update path could rebuild the runtime core-artifact manifest from the live ~/.nexo/scripts directory instead of the canonical npm package source. That reclassified personal scripts as core, hid them from portable export, and made runtime doctor treat personal LaunchAgents like unexplained drift. 5.3.9 heals that boundary directly.
Instead of scanning the live runtime tree during packaged updates, NEXO now resolves the canonical npm package src/ directory and rebuilds runtime-core-artifacts.json from that authoritative source. Personal files under ~/.nexo/scripts stop leaking into the core manifest.
The script registry now prefers the canonical packaged source when it is available, even if the runtime manifest was already poisoned by an older update. That means existing installs recover their personal-script classification instead of requiring manual cleanup or trusting a broken manifest forever.
Runtime doctor now restores personal script ownership before auditing unknown com.nexo.* LaunchAgents. Personal automations stop looking like unexplained core drift, and LaunchAgent inventory starts matching the real runtime again.
5.3.8 made the portability commands real on upgraded installs. 5.3.9 makes sure the same packaged update path does not silently erase the boundary between core runtime files and the operator's own automations. That boundary is what keeps daily work, export/import, and diagnostics trustworthy.
Real-machine validation of 5.3.7 exposed one last packaged gap: the npm package shipped nexo export / nexo import, but upgraded installs could still miss user_data_portability.py inside ~/.nexo because the runtime migrator only copied a manual allowlist of root modules. 5.3.8 closes that gap directly.
Instead of relying only on a static list, the packaged installer now scans src/ for top-level Python modules and carries them into the live runtime. New product surfaces stop getting stranded in the npm tarball while the existing install keeps running an older incomplete file set.
The user-facing effect is simple: when 5.3.8 ships a new root runtime module, upgraded packaged installs actually receive it. That is what makes commands such as nexo export and nexo import reliable after nexo update instead of only looking correct in docs and package contents.
A dedicated packaged-update regression test now asserts that the installer keeps discovering newly added root modules. Future releases have to preserve that behavior instead of silently omitting new files again.
5.3.7 fixed the packaged happy path and exposed portable continuity. 5.3.8 makes that work real on existing installs. Without this hotfix, the release story was coherent in GitHub, npm, docs, and website, but incomplete in the actual runtime the operator uses every day.
After fixing the Claude bootstrap path, the next real packaged-user gap showed up immediately on a real Mac: nexo update could still leave cron or LaunchAgent state needing a follow-up repair, and nexo doctor could stay red on tracked Codex drift even after the runtime itself was clean. 5.3.7 closes that happy-path gap and finally exposes explicit operator export/import commands for continuity.
After a successful npm bump, packaged installs now re-sync runtime cron definitions, skip same-file hook-copy noise when the runtime already points at its canonical source, and reload managed macOS LaunchAgents so the updated code is actually the code the machine runs.
nexo export writes a portable user-data bundle with the active DB, brain state, coordination artifacts, selected config, and personal scripts. nexo import restores that bundle into a clean runtime and creates a safety backup first instead of making continuity an implicit manual ritual.
Tracked historical Codex drift with zero open conditioned protocol debt now degrades instead of going critical, so cleaned packaged runtimes stop looking broken just because transcript history still exists.
5.3.6 fixed the Claude MCP bootstrap path. 5.3.7 is the release that makes that fix hold up in the normal packaged lifecycle too, so a real operator can update, restart, and keep working without having to know which extra repair command to run next or wonder whether doctor is describing the runtime honestly.
A practical patch release aimed at the real packaged path users actually live in. Claude Code now sees the managed NEXO MCP server from the user config it really reads, schedule status stops mislabeling open runs as broken, and runtime/release hygiene tightens around the edges that cause noisy drift.
Managed client sync now writes the NEXO MCP server to ~/.claude.json as well as Claude's managed settings file. That keeps nexo chat, claude mcp, and interactive sessions aligned on current Claude Code builds instead of leaving the runtime healthy but invisible.
nexo schedule status now treats in-flight jobs honestly, showing age and active/open-run state instead of collapsing every missing exit code into a failure. That makes long-running or keep-alive automation easier to trust at a glance.
Core-vs-personal script classification now reads more of the actual packaged/runtime surface, retroactive learnings stop opening keyword-only false positives outside their declared applies_to scope, and the final release-audit skill resolves repo roots more robustly across real operator layouts.
A small but important packaging honesty patch. NEXO already shipped an hourly built-in backup helper as part of the packaged runtime. Now nexo doctor inventories that helper as core too, so clean npm installs stop surfacing a false “unknown LaunchAgent” warning.
The packaged installer has treated com.nexo.backup as a core auxiliary LaunchAgent. Runtime doctor now uses that same inventory, instead of acting as if the built-in hourly DB backup helper appeared from nowhere.
This removes the last misleading warning from the packaged cleanup sequence. Users can install from npm, keep their data in ~/.nexo, and run nexo doctor without seeing a fake “unknown LaunchAgent” on an otherwise healthy runtime.
A trust-boundary patch for packaged users. NEXO now persists which scripts and hooks belong to the packaged core runtime, stops mixing them into the personal-script bucket, migrates the legacy Claude Code heartbeat wrappers into managed core hooks, and removes a stale public LaunchAgent template that was not backed by packaged core code.
Packaged installs now write a runtime core-artifacts manifest and the personal script registry reads it. If a file was shipped by the product, it is classified as core instead of being mixed into the operator's own script bucket just because it happens to live under ~/.nexo/scripts.
The remaining Claude Code heartbeat wrappers are shipped under the managed hooks surface. nexo update rewrites managed client configs to those hook paths and removes the retired legacy wrappers from NEXO_HOME/scripts.
nexo update Path
A patch release for real npm users. Installed runtimes now stay anchored to ~/.nexo, packaged bootstrap and client artifacts are refreshed after upgrade, repo-only release-artifact drift is skipped inside user installs, and personal-script/runtime path resolution stays on the canonical packaged home.
Packaged wrappers, helpers, hooks, and migrations now resolve the runtime from ~/.nexo instead of drifting back to legacy ~/claude assumptions or a local source checkout. A normal user install behaves like a normal user install again.
nexo update now refreshes packaged client/bootstrap artifacts after upgrade and keeps personal scripts, startup preflight, and doctor behavior aligned with the packaged runtime. Your data stays in ~/.nexo; the runtime stays replaceable.
nexo uninstall — Clean Runtime Separation
A new CLI command that cleanly separates runtime from user data. Stops all crons (LaunchAgents on macOS, systemd timers on Linux), removes the MCP server and hooks from Claude Code settings, deletes runtime files, and preserves all user data. Supports --dry-run to preview and --delete-data for full wipe.
Databases, learnings, brain calibration, personal scripts, operations logs — all preserved. Only core runtime files are removed. A .uninstalled marker tells the next npm install that existing data is waiting.
Instead of a hardcoded file list, nexo uninstall removes any .py/.txt at the NEXO_HOME root and known runtime directories. New core files added in future releases are automatically covered.
A patch release that fixes a datetime crash causing 7/8 Deep Sleep Phase 4 failures and closes the cortex decision→verification feedback loop by auto-creating outcomes when none exist.
_parse_any_datetime in apply_findings.py now explicitly strips timezone info with dt.replace(tzinfo=None), fixing a TypeError when comparing offset-naive and offset-aware datetimes during Phase 4. This bug caused 7 out of 8 Deep Sleep runs to fail on a single night.
cortex_decide() now auto-creates a decision_outcome when no existing outcome is linked to the task. The daily outcome-checker cron verifies these automatically, closing the decision→verification feedback loop that was previously open (linked_outcomes_total was always 0).
A focused minor release that closes two real gaps in the Cortex layer: the high-stakes detector was English-only with no way to reward well-prepared tasks, and the nexo-cortex-cycle cron was writing a quality snapshot that no reader ever consumed. Both loops close in this release. No breaking changes; no bootstrap, startup, Deep Sleep, or client-parity surfaces were touched.
HIGH_STAKES_KEYWORDS_ES adds ~45 Spanish keywords (crítico, producción, facturación, clientes, despliegue, credencial, privacidad, reembolso, and both accented and unaccented variants). A goal written in Spanish now trips the same high-stakes gate as its English twin — something like "migrar la base de datos de producción" used to silently skip the penalty.
NEGATION_PATTERNS suppresses the high-stakes flag when the text explicitly disclaims touching the sensitive area ("sin afectar producción", "no tocar prod", "without touching production", "don't modify"). Before this release these boundary statements caused false positives because the raw keyword was physically present.
evaluate_response_confidence now accepts pre_action_context_hits (+up to 10) and area_has_atlas_entry (+5). The score was a pure penalty accumulator before this release — there was no way to reward a task that did load the right context. Both signals are capped so they can never override a real risk penalty.
After the boolean high_stakes/unknowns/evidence/verification rules pick a mode, a monotonic safeguard downgrades answer to verify when final_score < 50 and verify to defer when high_stakes and final_score < 30. The safeguard can only make response discipline stricter, never looser — catching edge cases where soft penalties stacked below the threshold of any single rule.
The nexo-cortex-cycle cron has been writing $NEXO_HOME/operations/cortex-quality-latest.json every 6h since v5.1.0, with an explicit promise in its own docstring that "dashboards / morning briefings can read fresh metrics without re-running the SQL". That reader never existed. In v5.2.0, nexo_cortex_quality finally serves the cached snapshot for the 7d / 1d windows when the file is fresh (< 6h 30m), the schema matches, and the window is cached — otherwise it falls back silently to the live cortex_evaluation_summary computation.
The handler's response now includes "source": "cache" | "live" so callers (dashboards, morning briefings, agents) can see which path was taken without extra instrumentation. The cache is a performance optimisation, never a correctness dependency — any failure (missing file, corrupt JSON, stale timestamp, unknown schema, non-cached window) routes to live.
9 new tests in tests/test_protocol.py lock in Spanish detection, bilingual negation suppression, positive signal boosting, numeric safeguard transitions, and score bounds. 7 new tests in tests/test_cortex_quality_cache.py cover fresh cache hits, stale cache, corrupt schema, invalid JSON, missing file, and non-cached windows. Lint, security, coverage, release-readiness, and client-parity gates all green.
A focused patch that closes the gap where audit-phase workflow traces and self-audit placeholder goals silently accumulated in the runtime. No breaking changes; no bootstrap, startup, Deep Sleep, or client-parity surfaces were touched.
New runtime check flags stale audit-phase workflow_runs (over 6h open) and stale active WG-AUDIT-* / NEXO-AUDIT-* goals with no open runs, so drifted release traces become a visible degraded check instead of quietly piling up.
The daily self-audit now abandons WG-AUDIT-* placeholder goals after 36h via _retire_stale_audit_goals_inline(), marking them with an explicit blocker_reason. They are recreated only if the underlying pattern reappears.
episodic_memory.handle_session_diary_write now separates commit_ref gap warnings into recent (last 7 days) and historical buckets, so live drift stands out from dormant debt instead of being lumped together.
All three changes ship with dedicated tests and cleared Lint, Security, Release readiness, and Verify integrations / client-parity gates on PR #127.
v5.1.0 lands the full NEXO-AUDIT-2026-04-11 roadmap as a single coordinated minor bump. Evolution, adaptive, cognitive, and skills subsystems now close their own loops instead of leaving half-delivered signals inside the database. The knowledge graph exports cleanly, OpenTelemetry spans hook in when you want them, and every PR now has to clear lint, security, coverage, and release-readiness gates before it can merge.
Approved evolution proposals now auto-apply on the next cycle, adaptive rollbacks open visible followups instead of hiding inside adaptive_log, outcome patterns auto-promote to draft skills, and a Voyager-style detector surfaces co-occurring skill pairs as composite-skill candidates.
Search reranking now honours dream_weight and somatic markers as first-class signals. State watchers open deterministic NF-WATCHER-{id} followups and auto-resolve them, and correction fatigue surfaces as a visible followup instead of silently decaying memory.
A new Cortex quality cron runs every 6 hours, watches accept rate, linked-success rate, and override gap, and opens NF-CORTEX-QUALITY-DROP idempotently when the decision engine starts drifting between cycles.
Adding a new learning now walks recent decisions, scores them against the rule, and opens deterministic NF-RETRO-L<id>-D<id> followups for every decision the learning would have changed — exposed via nexo_learning_apply_retroactively.
The KG already tracked valid_from / valid_until on every edge. v5.1.0 adds nexo_kg_export with JSON-LD (using an nexo:* vocabulary) and GraphML output, and the as_of parameter replays historical snapshots for igraph, Gephi, NetworkX, and Cytoscape.
A new soft-import observability layer activates only when OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_SERVICE_NAME is set. When enabled, every tool call becomes a real span with ai.tool.* semantic attributes. When disabled, the wrapper stays a no-op so runtime cost is zero.
A new hook_runs table and nexo_hook_runs tool surface recent hook runs, failure streaks, and latency. Hook drops are no longer invisible.
New GitHub Actions workflows enforce ruff (E9/F63/F7/F82/F821), bandit at high severity/high confidence, coverage baselines for decay/trust/plugin loader, and verify_release_readiness.py --ci. A PR that breaks the release contract now fails loudly instead of waiting until tag push.
On a version bump, macOS installs now launchctl unload and reload every com.nexo.*.plist so long-lived crons pick up the new codebase immediately. auto_update is guarded by a POSIX flock with stale-steal at 10 minutes so two concurrent nexo update runs cannot stomp each other.
The new benchmarks/results/comparison-vs-competition-2026-04.md lays out where NEXO wins, where it is on par, and where peers lead — across Letta, Mem0, Zep, Graphiti, Cognee, and DSPy. No cherry-picking.
v5.0.4 closes the next small post-5.0 runtime gap. The vendorable helper path used by personal scripts is now more robust, the doctor stops degrading on one-off advisory telemetry noise, and simple read/respond flows are pushed harder to answer after the first relevant artifact instead of feeling hung.
templates/nexo_helper.py now resolves NEXO_HOME and the nexo CLI robustly, so personal scripts and subprocess flows stop failing because one runtime happened to be launched from a different environment.
Advisory self-audit warnings stay advisory, and a single missing usage-telemetry row no longer degrades the full runtime. Real drift still shows up; one-off noise no longer poisons the top-line health signal.
The managed Claude/Codex bootstraps now tell NEXO to answer visibly after a single email, diary, reminder, or followup read before chaining extra lookups, which removes a chunk of the “looks hung” feeling on basic retrieval tasks.
The vendorable bridge now includes a canonical JSON-returning automation helper, so personal scripts no longer need brittle ad-hoc parsing when they depend on structured backend output.
v5.0.2 is a focused hotfix release for the post-upgrade deep-doctor path. Healthy installs using the current learnings schema could still show a misleading skipped check because the doctor was reading the old archived column. This patch restores schema-aware auditing and revalidates the corrected path on a real upgraded runtime.
The deep doctor now reads both the modern status-based learnings schema and the older archived flag instead of assuming one historical shape forever.
The patched path was re-tested on a live upgraded install with nexo update, nexo doctor --tier deep, and nexo doctor --tier all.
A fresh Claude Code startup smoke returned OK STARTUP after the sync, so the hotfix ships with runtime evidence instead of only a unit-test story.
v5.0.1 is a hotfix release focused on the live upgrade path. Older installs could preserve obsolete managed Claude Code hooks and show warning storms that looked like a hung runtime even when the core system was healthy. This patch removes only that stale managed drift and revalidates the path on a real install.
client_sync now removes obsolete managed Claude Code hook identities, such as the old heartbeat-guard.sh path, when they no longer belong to the published core hook set.
The cleanup is narrow on purpose: custom local hooks remain untouched while stale core-managed entries are removed, so operators do not lose their own local behavior.
The corrected path was re-tested on a live install with client sync, Codex and Claude Code headless runtime access, email-monitor recovery, lifecycle health checks, and a full nexo update.
v5.0.0 connects the pieces that used to live too far apart: goal profiles influence decisions, decisions link to measured outcomes, repeated winning patterns can seed reusable skills, and the public benchmark/story now reflects that broader runtime truth instead of a memory-only snapshot.
Decision evaluation now carries explicit goal profiles, ranks alternatives with stronger rationale, and keeps the recommendation trace tied to the operator's active objective instead of pretending every decision has the same goal.
Outcomes are no longer only logs. Repeated successful strategies can now seed reusable skills, while weak evidence can demote or retire bad patterns before they calcify into cargo cult procedures.
The operator runtime pack now scores 96.2% for the NEXO full stack across 13 checked-in scenarios, while LoCoMo remains the memory-specific benchmark. Public proof now has the right scope instead of stretching one metric too far.
The release contract, runtime doctor, update path, protocol debt maintenance, and public website are aligned as one audited package. The point is not only more capability, but less drift between what ships, what runs, and what is claimed.
A new Drive/Curiosity layer gives NEXO internal motivation. During normal work, it passively detects anomalies, recurring patterns, knowledge gaps, and opportunities. These observations accumulate as tension-based signals that mature over time and trigger autonomous investigation — without blocking the operator or adding latency.
Five signal types — anomaly, pattern, connection, gap, opportunity — follow a lifecycle: latent → rising → ready → acted/dismissed. Signals decay daily unless reinforced, and ready signals are investigated silently.
nexo_drive_signals, nexo_drive_reinforce, nexo_drive_act, and nexo_drive_dismiss expose the drive surface publicly while internal detection runs passively from heartbeat and task close.
Overnight synthesis now includes a Drive phase: investigating ready signals, promoting cross-area connections, and dismissing stale signals. Findings are applied automatically.
Detection now starts from LLM classification with controlled semantic/regex fallback, so the Drive surface is less fragile across languages and paraphrases than the first launch version.
v4.0.1 is the patch that makes the public truth catch up with main. The full 4.0 memory-surface release now ships coherently across git installs, npm, GitHub Releases, and the public website, and it adds a correction-aware reminder so learning capture stops depending only on model discipline.
The post-v4.0.0 fix that landed on main is now packaged as a real patch release instead of leaving git installs ahead of the published tag and site copy.
tools_sessions now emits a LEARNING REMINDER when an operator correction is visible and no recent learning capture appears nearby, making the protocol more self-enforcing.
This patch does not shrink the broader 4.0 package. Multimodal refs, pre-compaction auto-flush, the public claim wiki, readable export, user-state inspection, and retrieval/backend controls all remain the current public story.
v4.0.0 turns more of NEXO memory into explicit product surfaces instead of hidden implementation detail: multimodal artifact references, structured continuity before compaction, a public claim wiki, readable memory export, richer user-state adaptation, and clearer retrieval/backend controls.
New tools nexo_media_memory_add, search, get, and stats give screenshots, PDFs, audio, video, and other non-text artifacts a first-class home in the memory model.
The pre-compact hook now writes structured continuity records and feeds recent context through nexo_auto_flush_recent and nexo_auto_flush_stats, so important session state is less likely to vanish during compression.
The claim graph is now a public provenance/freshness surface through nexo_claim_*, and nexo_memory_export can emit an auditable markdown bundle instead of forcing operators to trust only hidden DB state.
nexo_user_state combines trust, correction fatigue, sentiment, diary signals, and hot-context pressure into an inspectable adaptive surface, not just keyword mood detection.
nexo_cognitive_retrieve now exposes more public control over hybrid weighting, decomposition, dream exclusion, and dormant-memory handling instead of keeping those decisions buried internally.
v4.0.0 also folds in the unreleased post-3.2.0 work: safer live-repo automation boundaries, richer tool explanations, the Deep Sleep import-path repair, and stronger core-vs-personal ownership around updater/doctor LaunchAgent handling.
v3.2.0 closes the gap between "we definitely discussed this today" and "the runtime can actually recover it". Hot context remains the first recent-memory layer, but recent transcripts are now accessible through MCP when that layer is too thin, and NEXO can inspect its own runtime surface through a live generated catalog.
New MCP tools nexo_transcript_recent, nexo_transcript_search, and nexo_transcript_read make recent Claude Code / Codex transcripts reachable when hot context and durable recall are not enough.
The public transcript fallback and overnight Deep Sleep now use the same transcript parser, which keeps operator-visible recovery and overnight analysis on the same raw session truth.
New tools nexo_system_catalog and nexo_tool_explain generate a runtime map from canonical sources: core tools, plugins, skills, scripts, crons, projects, and artifacts.
v3.1.9 closes the last gap in the hot-context rollout: `nexo update` now discovers root runtime modules dynamically, so adding a new top-level tool no longer breaks upgrade verification on already installed runtimes.
The updater no longer relies on a frozen allowlist for root `.py` modules. New runtime modules now ship automatically with normal updates.
This specifically fixes the bootstrap hole where `server.py` expected `tools_hot_context.py` but older installed updaters did not know how to copy it into the runtime.
Runtime-update coverage now asserts that `tools_hot_context.py` is copied into installed runtimes, so future releases cannot silently regress the same delivery path.
The first hot-context tag exposed CI-only regressions before publication. v3.1.8 is the stable public release: the same 24-hour recent-memory model, now backed by a green full suite, reload-safe DB state, and additive fallback behavior when partial schemas exist.
The public release now reflects the fully validated hot-context stack instead of an orphan pre-release tag that failed CI after the tag was already pushed.
The modular `db` package now refreshes submodules correctly and resolves live core access dynamically, so DB switches in tests and runtime repairs do not leak stale module state.
Hot-context capture degrades cleanly when minimal tables exist, which keeps self-audit and reminder/followup flows working even before the recent-memory tables are present.
v3.1.7 adds a first-class recent-memory layer to NEXO. Instead of hoping the runtime can reconstruct the last few hours from diaries and durable recall alone, active topics now live in a shared hot-context substrate with recent events, pre-action loading, and dashboard visibility.
Core now persists hot contexts and recent events so the runtime can rehydrate what was actively happening in the last day across sessions, channels, and clients.
New MCP tools let agents load recent continuity before acting, capture active topics when work starts or blocks, and resolve them when the situation is actually closed.
The memory page now exposes `Hot Context 24h`, and the dashboard reminder/followup APIs no longer bypass history discipline because update/delete/move paths require a fresh `READ_TOKEN`.
v3.1.6 closes a subtle but public operational gap: abandoned-project discoveries are no longer created as live pending followups. They now land as archived historical context with an explicit note, so NEXO keeps the memory without polluting active queues.
Deep Sleep stops creating abandoned-project findings as active `PENDING` work, which removes another source of noisy resurfacing in followup-driven flows.
The item is still preserved as a followup row, but it starts archived and includes a history note explaining that Deep Sleep intentionally stored it as historical context.
A dedicated regression test now asserts that abandoned followups stay archived and non-actionable across future releases.
v3.1.5 finishes the history-aware reminder/followup rollout on the visible operational surfaces: dashboard filters now expose open, completed, deleted, and full-history views cleanly, and proactive scans stop reviving work that is already inactive.
The operations dashboard now distinguishes default open work from completed, deleted, and full-history views instead of collapsing everything into a vague catch-all status.
Reminder and followup API filters now treat status families consistently, which keeps dashboard screens and backend list endpoints aligned on what counts as open, completed, deleted, or historical work.
The proactive dashboard stops flagging deleted, waiting, cancelled, archived, blocked, or completed items as overdue, removing another source of operational zombie state.
v3.1.4 closes the last blind spots after the history-aware reminder/followup release: core automation jobs now preserve operational history too, followup priority is handled at creation time, and self-audit learning auto-capture no longer depends on a fragile reread path.
Daily self-audit, Deep Sleep apply, and weekly followup hygiene now leave proper reminder/followup history behind instead of mutating rows silently inside core automation.
Followup priority is now part of the creation path itself, which removes the last raw post-insert server patch and keeps creation semantics consistent with the history-aware CRUD model.
Self-audit repair learning capture no longer depends on a brittle refresh-after-update pattern, so inline repair learnings are safer in long-lived runtimes and multi-step maintenance flows.
v3.1.3 turns reminders and followups into history-aware operational records instead of disposable rows: mutations are logged, delete becomes soft delete, and the public MCP surface now forces a read-before-mutate flow for risky changes.
Each reminder and followup now records created, updated, completed, deleted, restored, note, and recurring archive/spawn events so agents can see the operational timeline instead of overwriting context.
Delete no longer destroys reminders or followups. Completed and deleted items remain available for later lookup, which lets NEXO reason over what happened before instead of forgetting it permanently.
New get/note/restore tools expose history and a short-lived read token. Update/delete/restore/note flows now require that token, so agents have to read the item history before changing it through MCP.
v3.1.2 is a focused patch release that spreads managed Evolution runs across the week, closes a runtime-update gap around top-level protocol modules, and verifies that new learnings actually persist after insert.
Managed installs no longer schedule public Evolution on the same Sunday slot. Each machine now derives a stable weekly position, which spreads PR creation and review load across the week.
nexo update now carries top-level runtime modules like hook_guardrails.py and protocol_settings.py, so protocol-discipline behavior does not drift just because the source repo moved but the runtime root did not.
Creating a learning now reads it back immediately from storage and returns an explicit persistence failure if the new active row cannot be verified.
v3.1.1 is a targeted patch release that restores safe runtime updates on installations with multiple personal scripts sharing the same logical name, such as paired Python and shell implementations of the same workflow.
The personal script registry now derives stable IDs from the script path first, so two different files can share the same logical `name` without breaking `nexo update` or runtime reconciliation.
This specifically fixes the case where installations keep both `.py` and `.sh` variants of the same automation and the runtime update flow previously aborted while reconciling personal scripts.
The self-audit corrective runtime, public-port queue, stricter onboarding, Docker setup, workflow docs, and benchmark surfaces from v3.1.0 remain the main feature release underneath this patch.
v3.1.0 turns self-audit from a ticket generator into a corrective runtime surface, adds stricter onboarding paths for new users, and broadens the public product surface with clearer client docs, container setup, workflow examples, and benchmark artifacts.
Contradictions, formalizations, and prevention gaps now resolve during the audit itself, while mechanical cleanup handles managed bootstraps, watchdog registry drift, golden snapshots, and syntactically broken personal plugins.
When self-audit fixes a public-core path inline, NEXO queues a durable public-port candidate so the weekly public Evolution cycle can still carry that improvement into the open product instead of losing it inside private maintenance.
New `protocol_strictness` modes, Gemini/Cursor/Windsurf setup guides, Docker Compose with persistent state, workflow quickstart examples, and a starter benchmark package make NEXO easier to adopt and easier to evaluate.
v3.0.2 is a concentrated patch release focused on making opt-in public contribution safer and on removing a whole class of reliability issues across cron, catchup, doctor, migrations, and other SQLite-heavy runtime surfaces.
Machines now resume contribution immediately after maintainers resolve a Draft PR, preserve active PR metadata correctly, and avoid false-positive diff sanitization on valid Linux-facing paths.
Linux weekday mapping now respects the launchd-style manifest convention, and catchup keeps its lock until the full run completes while still releasing that lock correctly on early crashes.
Backup/restore, doctor providers, state watchers, evolution-cycle data gathering, KG backfill, embedding migration, and other runtime paths now close SQLite connections reliably even when intermediate steps throw.
v3.0.1 is a surgical patch release: it restores Python 3.10 compatibility for repo-based runtime surfaces and strengthens boot-tier validation so broken config artifacts stop failing silently.
Python 3.11-only datetime.UTC usage in live runtime paths now falls back to Python 3.10-safe timezone handling, so repo-based nexo chat and startup flows stop dying at import time.
tomllib FallbackRuntime modules that parse TOML now use tomllib on 3.11+ and tomli on 3.10, with the fallback dependency declared for fresh installs.
Boot checks now validate schedule.json, optionals.json, and crons/manifest.json, catching silent config corruption before it degrades cron behavior later.
v3.0.0 turns NEXO from a strong memory layer into a stricter cognitive runtime. Protocol discipline is now enforced by runtime tools, durable workflows and goals can survive interruption, conditioned learnings behave like real guardrails, and public scorecards finally show measured cost/recovery data instead of only architecture claims.
nexo_task_open, nexo_task_close, persistent protocol_debt, simplified bootstraps, and enforceable Cortex gates make verification and discipline part of the runtime contract.
NEXO now ships resumable workflows, checkpoints, replay, retry bookkeeping, idempotent open keys, human approval gates, compensation metadata, and durable goals for long multi-step work.
Critical file learnings now gate read/edit/delete paths across Claude hooks, Codex transcript audits, and headless automation prompts, while contradictory active rules are superseded instead of piling up.
Deep Sleep schema drift is hardened, warning storms degrade health even on exit 0, keep-alive jobs report alive/degraded/duplicated honestly, and release-readiness now validates against the active runtime home.
The compare scorecard now includes external baselines, NEXO ablations, runtime telemetry coverage, and cost_per_solved_task when the collected data is representative.
If a machine already has its own Draft PR open, public-core Evolution now reuses the cycle to peer-review other opt-in PRs safely instead of doing nothing.
NEXO now measures the Deep Sleep engineering loop instead of treating it like a black box. Periodic summaries expose protocol compliance, engineering output, project pressure, and trend-vs-previous data, while runtime doctor and release tooling enforce that operational truth before publish.
Weekly and monthly summaries now include protocol compliance, engineering followup counts, project pulse, and period-over-period trend data.
The dashboard now surfaces What Matters Now, What Is Drifting, and What Is Improving directly from the latest periodic summaries.
Runtime doctor now audits heartbeat, guard_check, and change_log compliance from the latest weekly summary instead of leaving protocol drift implicit.
scripts/verify_release_readiness.py now enforces changelog/version alignment, synced release artifacts, parity checks, and website drift before release.
The unreleased Codex launcher fixes after v2.6.21 are now shipped too: better client selection, corrected launch mode handling, last terminal choice tracking, and aligned interactive flags.
Deep Sleep now does more than diagnose recurring problems. It semantically deduplicates followups, consolidates learnings into stronger canonical records, flags contradictions for review, and backfills explicit engineering followups when a recurring pattern implies a concrete script, hook, checklist, or guardrail.
Nightly followups are now checked against existing open followups semantically, not just by generated ID, and a matched followup can be upgraded in place when the new proposal is more concrete.
New learnings are classified as duplicate, reinforcement, contradiction review, or genuinely new instead of always creating another row.
Recurring medium/high-severity patterns can now backfill concrete engineering followups automatically even when the raw synthesis would otherwise stop at diagnosis.
NEXO now treats Claude's recommended profile as an explicit runtime contract instead of a loose alias: fresh installs default to Opus 4.6 with 1M context, existing runtimes can be normalized to that profile safely during update, and the same Claude profile now applies consistently to interactive sessions and headless automation.
The installer and normalized runtime defaults now use claude-opus-4-6[1m] instead of the generic opus alias.
The Claude model picker now recommends Opus 4.6 with 1M context directly, instead of the vaguer “Opus latest” wording.
Claude automation runs now resolve legacy task hints like model="opus" and model="sonnet" through the configured Claude runtime profile, so the selected model actually governs both chat and background work.
2.6.18 closes the practical roadmap items after bootstrap parity: Codex now keeps a managed MCP contract in config, runtime doctor audits real recent sessions, Deep Sleep writes higher-horizon summaries, and retrieval explains itself more honestly while staying cleaner on exact lookups.
mcp_servers.nexoCodex sync now persists a managed shared-brain MCP entry in ~/.codex/config.toml, instead of depending only on ad-hoc CLI MCP state.
Runtime doctor now checks recent Codex sessions for startup discipline and verifies Claude Desktop shared-brain metadata explicitly.
Deep Sleep now writes reusable weekly and monthly summary artifacts and weighs projects by activity, learnings, followups, and decisions.
Retrieval responses now expose confidence and the auto-strategy that fired, while associative expansion trims low-signal neighbors back to top_k.
Deep Sleep now accepts the nested synthesis output path produced by the current headless model flow, removing a false overnight failure mode.
2.6.16 made Codex startup state much stronger. 2.6.17 fixes the last migration edge cases for real existing installs: Codex-linked runtimes now backfill correctly during update, blank operator names no longer break managed bootstrap docs, and the repaired client state gets persisted for later updates.
Older installs that already had NEXO wired into Codex now infer that state during normalization so shared-client sync does not quietly skip Codex anymore.
Managed CLAUDE.md and AGENTS.md now fall back to the operator name NEXO when local metadata is blank or missing.
Runtime update flows now write the normalized client preference back to disk before syncing clients, so the fix survives future updates instead of only helping one command.
2.6.16 improves both cognition and multi-client realism: Codex gets managed global bootstrap/model sync, retrieval becomes smarter by default, and Deep Sleep now reasons across a blended 60-day horizon instead of focusing only on the recent past.
NEXO now syncs the live bootstrap, model, and reasoning profile into ~/.codex/config.toml, not just ~/.codex/AGENTS.md.
Startup/session coordination and dashboard followups are now client-aware instead of assuming every interactive session is Claude-shaped.
Conceptual queries now auto-enable HyDE and shallow spreading activation, while exact lookups stay conservative.
STM/LTM memories now track their own stability and difficulty on top of the Ebbinghaus base curve.
Overnight synthesis now mixes recent and older context across diaries, learnings, transcript metadata, and stale followups to surface multi-week patterns.
New tests now guard key shared-runner, transcript-source, bootstrap, and followup paths against drifting back into Claude-only assumptions.
2.6.14 shipped the parity model. 2.6.15 hardens it for real installations by fixing bootstrap template resolution in packaged/runtime layouts, so existing users actually receive the managed Claude/Codex bootstrap updates.
bootstrap_docs.py now resolves templates/ correctly in both source-tree and installed-runtime layouts.
Managed updates to ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md now land correctly in real installations instead of failing silently.
New tests cover runtime-layout template resolution and isolate startup-preflight HOME usage so local test runs do not contaminate real user bootstrap files.
Shared brain now reaches startup identity and overnight analysis, not just MCP wiring. Claude and Codex both get managed bootstrap docs, Codex starts explicitly as NEXO, and Deep Sleep reads both transcript stores.
NEXO now manages both ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md as first-class bootstrap files.
CORE / USER ContractBootstrap docs now preserve operator instructions in a protected USER section while allowing NEXO updates to refresh product rules in CORE.
nexo chat and Codex headless automation inject the live bootstrap explicitly, so Codex no longer behaves like plain Codex with an MCP attached.
Overnight analysis now reads Codex durable sessions alongside Claude transcripts, with client/source metadata and stable per-session mapping.
Runtime doctor now checks bootstrap parity and transcript-source parity instead of assuming a Claude-only world.
Evolution, watchdog, and self-audit now treat AGENTS.md as protected alongside CLAUDE.md.
NEXO now supports personal helper daemons as official managed schedules. Legacy wake-recovery installs are adopted automatically, which removes false criticals and improves runtime self-healing.
keep_alive SupportPersonal scripts can now be declared as official KeepAlive daemons instead of being limited to interval or calendar schedules.
restart_daemon Recovery PolicyNew recovery contract for personal helpers that should stay alive continuously and restart automatically after sleep, wake, or process loss.
nexo-wake-recovery is backfilled with inline metadata automatically, then reconciled as a managed personal schedule instead of being treated as a strange orphan.
nexo doctor --tier runtime --fix can now leave the runtime genuinely healthy in this scenario instead of stopping on a misleading personal-script critical.
NEXO now separates shared brain, interactive client, and automation backend. Claude Code remains the recommended path, but Codex is now supported as both terminal client and background backend, and Claude Desktop can share the same brain.
nexo chat No Longer HardwiredThe runtime can open the configured terminal client instead of always launching Claude Code. Manual override also supported.
NEXO now persists interactive clients, default terminal client, automation backend, install preferences, and runtime model profiles.
Background jobs now go through a shared runner, so core agentic processes can execute under Claude Code or Codex without every script hardcoding provider-specific calls.
Current defaults: Claude Code on Opus 4.6 with 1M context, Codex with GPT-5.4 xhigh. Claude Code is still the most mature and hook-rich integration.
Your scripts become first-class citizens with 9 MCP tools for lifecycle management. NEXO Brain is now structured as a Claude Code plugin. The Day Orchestrator has been decoupled from core to reduce complexity.
Scripts in NEXO_HOME/scripts/ are tracked in SQLite with metadata, categories, and schedule associations. 9 MCP tools: list, create, remove, reconcile, sync, classify, schedule, unschedule, ensure_schedules. Full lifecycle management.
Added plugin.json, entry point, and packaging structure for the Anthropic Claude Code plugin marketplace. NEXO Brain can now be discovered and installed as a first-class Claude Code extension.
Evolution can now modify core behavior modules (not just config) when running in managed mode. Automatic rollback followups ensure safe self-improvement. Fixed false-positive watchdog tamper detection.
nexo chatOfficial CLI command to launch Claude Code with NEXO as operator. Supports directory arguments. Runtime version now correctly surfaces in installed environments.
The Day Orchestrator (autonomous headless cycles every 15 min) has been removed from the core product. Reduces complexity for standard installs. Power users can keep it as a personal script.
Hardened cron runtime recovery with TCC diagnostics. Keepalive sync alignment. Disabled optional crons correctly respected. Personal schedules handled during boot recovery. Duplicate learning prevention.
Automated version synchronization across Claude Code plugin, OpenClaw package, and ClawHub skill. Full GitHub Actions CI/CD pipeline for verified multi-channel publishing.
Automated version synchronization across Claude Code plugin, OpenClaw package, and ClawHub skill before every publish. No more version drift between distribution channels.
Full GitHub Actions workflow: sync → verify Claude packaging → verify ClawHub → build/test OpenClaw → publish npm + OpenClaw + ClawHub → post-publish verification.
Contract tests, correct runtime path (~/.nexo/server.py), explicit exports and files list. Published as @wazionapps/openclaw-memory-nexo-brain@2.6.9.
Version-synchronized metadata, correct server path, post-publish smoke verification. Install resolves to 2.6.9.
Verified plugin.json, .mcp.json, hooks, server.py included in npm tarball. Marketplace-ready.
Opt-in public contribution mode, personal MCP plugin scaffolding, clearer install/update progress, and wider diary continuity windows.
Added opt-in public contribution mode for install/update on GitHub-authenticated machines. Uses isolated checkout, dedicated public_core evolution policy, opens single Draft PR before pausing. Contributor lifecycle via nexo contributor status|on|off with guardrails blocking personal data, prompts, logs, secrets from proposals.
Added nexo_personal_plugin_create tool for scaffolding persistent personal MCP plugins in NEXO_HOME/plugins with optional companion script. Reusable template survives updates without becoming core.
Clearer install/update progress (file copy, migrations, schedule reconciliation, verification). nexo_session_diary_read(last_day=true) returns ~36h continuity window instead of truncating to calendar day. Auto-close diary promotion preserves more goal/next-step/reasoning context.
The nexo binary becomes a real runtime CLI. Background jobs declare explicit recovery contracts. Platform-aware power policy prevents missed schedules.
nexo chat launches Claude Code with NEXO as operator. nexo update syncs the cognitive engine. nexo doctor runs unified diagnostics. One binary for full control.
Every background job declares its recovery behavior: skip, catch-up, or re-run. Boot and wake scripts honor these contracts — no silent failures after sleep or restart.
Health checks and safe migrations before every interactive session. Dependency verification, environment validation, and stale lock cleanup ensure a clean start.
macOS power assertions, Linux sleep inhibit, and intelligent scheduling that adapts to battery state. Background processes respect platform power constraints.
Evolution can modify core behavior modules with automatic rollback followups. Fixed false-positive watchdog tamper detection. Safer self-improvement cycles.
Tool count grows from 144 to 150+ with new personal script lifecycle tools, doctor diagnostics, and recovery management. All exposed via the standard MCP protocol.
Scripts in NEXO_HOME/scripts/ become first-class managed entities with full lifecycle tracking, schedule associations, and classification.
9 MCP tools for script lifecycle: list, create, remove, reconcile, sync, classify, schedule, unschedule, ensure_schedules. SQLite-backed metadata with categories.
Automatic categorization of scripts by purpose: core, monitoring, maintenance, reporting, integration. Used for recovery priority and schedule grouping.
Scripts linked to cron schedules with proper lifecycle. Unscheduling a script cleans up the cron entry. Ensure_schedules validates all associations on boot.
nexo chat & Claude Code Plugin StructureThe official CLI command to launch Claude Code with NEXO as operator. Plugin packaging for the Anthropic marketplace.
nexo chatOfficial CLI command to launch Claude Code with NEXO as operator. Supports directory arguments. Runtime version correctly surfaces in installed environments.
Added plugin.json, entry point, and packaging structure for the Anthropic Claude Code plugin marketplace. NEXO Brain discoverable as a first-class extension.
The Day Orchestrator removed from core to reduce complexity. Available as a personal script for power users. Standard installs are leaner.
Deep Sleep now creates reusable skills automatically, every cron execution is tracked, and the system passed a 5-phase automated audit covering product, failure handling, security, packaging, and UX.
Deep Sleep extracts multi-step procedures from sessions and stores them as skills with full content (steps, gotchas, markdown). Trust pipeline: trace→draft→published→archived. 7 MCP tools for skill management.
Every cron execution tracked in cron_runs table. nexo_schedule_status shows what ran overnight. nexo_schedule_add creates new crons from conversation. Universal wrapper for all processes.
Watermark-based collection (late-night sessions never missed). Per-session checkpointing (crash-safe resume). Retry x3 on failure. Auto-calibration of personality settings from emotional analysis.
Credential redaction in tool logs. Transcript sanitization in Deep Sleep. Command injection fix in dashboard. Path traversal protection in plugin loader. 5-phase audit passed.
Startup only shows human-interactive sessions. Automated cron diaries filtered out. Email sessions preserved as real interactions. Auto-closed sessions with heartbeats kept.
from __future__ import annotations across 18 files for Python 3.9 compat. Full systemd timer support. Bash alias written to .bashrc for Linux users.
A 4-phase overnight pipeline with emotional analysis, abandoned project detection, and declarative cron management. The agent now adapts its personality based on yesterday's emotional signals.
Complete rewrite of the overnight analysis system. Collect splits transcripts into individual session files. Extract runs Claude per session to find uncaptured findings. Synthesize merges cross-session patterns. Brief generates a structured morning briefing with priorities.
Each session's emotional profile (frustration, flow, urgency, satisfaction) is analyzed and stored in session-tone.json. On startup, smart_startup reads tone data and adapts the agent's next-day behavior automatically.
Deep Sleep extracts: uncaptured corrections, protocol violations, missed commitments, user preferences, recurring patterns, emotional signals, abandoned projects, and productivity insights. Each with severity scoring and recommended actions.
All autonomous processes declared in cron-manifest.json with schedules, descriptions, and platform configs. nexo_update automatically syncs LaunchAgents/systemd timers after code updates. No manual plist editing.
Deep Sleep identifies projects mentioned in sessions that have gone silent — no commits, no mentions, no followups. Surfaces them in the morning briefing with context.
All Claude CLI calls unified to 6h (21600s) safety net. Fixes premature termination of long-running processes like deep-sleep, immune, and synthesis. Added NEXO_HEADLESS=1 to all background scripts.
Code and data fully separated. 13 core recovery-aware jobs auto-installed. Auto-update on startup. Auto-diary captures everything. 150+ MCP tools. 12 rounds of external audit with ~60 findings resolved.
Code lives in the repo, personal data in NEXO_HOME (~/.nexo/). Clean separation means updates never touch your data and multiple agents can share the same codebase.
All processes auto-installed: watchdog, immune, synthesis, backup, catchup, cognitive-decay, postmortem, self-audit, sleep, deep-sleep, evolution, followup-hygiene, prevent-sleep, tcc-approve, auto-close-sessions. Plus 7 hooks.
Non-blocking update check (5s max) on every server start. Resilient to network failures. Opt-out via schedule.json. No more manual npm updates.
3-layer diary system: PostToolUse writes every 10 calls, PreCompact catches emergencies before context eviction, heartbeat triggers on DIARY_OVERDUE. Never lose session context again.
Customizable process schedules with timezone support. Control when each autonomous process runs. Override defaults without editing plist/timer files.
Memory decay was 24x too aggressive. STM half-life corrected from 7 hours to 7 days, LTM from 2.4 days to 60 days. Memories now persist as intended.
Section markers for safe core updates without losing user customizations. The installer updates its own sections and preserves everything else.
12 rounds of audit by GPT-5.4, Gemini 2.5, and Claude Opus. ~60 findings resolved: guard noise, MCP truncation, decay values, import errors, legacy paths, and more.
NEXO Brain is now fully English, fully cross-platform, and ready for any user. All UI strings, DB status values, and paths are internationalized. Linux gets first-class automated processes via systemd or crontab.
All 39 source files translated to English. DB status values: PENDING, COMPLETED, DELETED. Zero Spanish in user-facing output. Onboarding still supports 7 languages.
systemd user timers (preferred) or crontab fallback. Same 4 automated processes as macOS: cognitive decay, postmortem, sleep, self-audit. Platform auto-detected during install.
Change log entries automatically cross-reference open followups by file overlap, keyword similarity, and ID reference. Matching followups are completed automatically.
Learning categories are no longer hardcoded. Use any category name that makes sense for your project: backend, frontend, devops, or anything else.
494 to 127 lines. Same capabilities, compact procedural format. Heartbeat signal reactions, Cortex modes, and Adaptive personality all documented.
All hardcoded paths replaced with NEXO_HOME env var. Zero personal data in the codebase. 48 macOS Finder duplicate files deleted.
NEXO Brain now ships with a complete autonomous nervous system of 11 background scripts, a redesigned visual dashboard, 13 LaunchAgent templates for zero-config setup, and a full migration script from v1.5.
Immune system, daily synthesis, self-audit, postmortem consolidator, proactive dashboard, followup hygiene, GitHub monitor, catch-up. Updated: watchdog, evolution, cognitive decay, deep sleep.
FastAPI-powered visual interface with 6 pages: dashboard overview, operations, calendar, inbox. CRUD UI for managing memories. Sidebar navigation, trust widget, static assets.
Ready-to-install macOS plists: watchdog, immune, synthesis, self-audit, cognitive decay, evolution, deep sleep, followup hygiene, auto-close, dashboard, catch-up, postmortem, GitHub monitor. Includes README install guide.
Session-stop v7 (post-mortem), session-start (semantic context), inter-terminal inbox hook, capture-tool-logs (JSONL), daily-briefing-check.
Automated v1.5 to v1.6 migration: 13 nexo.db schema migrations, cognitive.db tables, full i18n (Spanish to English), logo optimized 1.4MB to 28KB.
NEXO Brain now reads your complete session transcripts overnight, finding what the agent missed during the day. Plus: the watchdog can re-execute missed crons and verify its own repairs.
Reads every message, tool call, and correction from the day's sessions. Finds uncaptured corrections, protocol violations, missed commitments, and quality issues. Applies findings as learnings, feedback memories, followups, and trust adjustments.
Uses Claude CLI in bare mode to analyze each session independently. No hooks, no CLAUDE.md interference. Processes 10+ sessions per night with catch-up for missed days.
When a scheduled cron misses its run (Mac was asleep), the watchdog extracts ProgramArguments from the plist and re-executes it directly. No more lost nightly jobs.
After Level 2 Claude CLI repair, the watchdog waits and verifies the fix actually worked — checks loaded state, process running, and log freshness. No more silent failures.
The two largest files are now modular packages. Search is smarter with Knowledge Graph boosting. Vector indexing scales to 10K+ memories. Claims decompose blobs into verifiable atomic facts. Terminals talk to each other automatically.
db.py (2,900 lines) → db/ package with 11 modules. cognitive.py (3,900 lines) → cognitive/ package with 6 modules. All imports unchanged — zero breaking changes.
Memories connected to more Knowledge Graph nodes rank higher. Logarithmic boost based on structural importance bridges semantic and graph retrieval.
Optional hnswlib integration for approximate nearest neighbor search. Auto-activates when memory count exceeds 10,000. Hooks into ingest, search, and GC.
Decompose blob memories into atomic verifiable claims with provenance, contradiction detection, and verification status. Each fact tracked individually.
PostToolUse hook checks inbox automatically via sqlite3. 2-second debounce, skips read-only tools. Zero tokens consumed when no messages waiting.
24 pytest tests covering migrations, CRUD, cosine similarity, KG boost, knowledge graph traversal, and temporal boost. Isolated temp databases per test.
All 9 nightly processes now use Claude CLI (opus) for intelligent decisions instead of Python word-matching. Plus: 3 bugs found by giving GPT-5.4 and Gemini 2.5 full access to the codebase.
Pure Python collects data, then Claude CLI opus makes intelligent decisions. The brain uses its own intelligence to dream — not a calculator.
GPT-5.4 (Codex CLI) + Gemini 2.5 (Gemini CLI) + Claude Opus reviewed the full codebase simultaneously. Found 3 real bugs with exact file:line references.
Retrieved memories are now sanitized to prevent prompt injection. Stored content is treated as quoted evidence, not executable instructions.
The quarantine system now distinguishes confirmation from contradiction. Similar memories that reinforce each other are no longer rejected as conflicts.
NEXO can now evolve its own configuration autonomously through a structured proposal → review → implement cycle. Dual-mode operation ensures safety: auto mode for low-risk changes, review mode requiring explicit approval.
Auto mode applies low-risk improvements (nightly job tuning, threshold adjustments) without intervention. Review mode stages proposals for human approval before execution.
Evolution proposals are generated from session patterns, guard stats, and cognitive metrics. Each proposal includes rationale, risk assessment, and rollback plan.
Proposals are executed via Claude CLI for safe, auditable implementation. Every change is logged and reversible.
Nightly jobs now detect and merge duplicate learnings automatically. Test/debug STM memories are purged during cognitive decay.
NEXO Brain is now licensed under AGPL-3.0. This ensures that any modifications to the cognitive memory system remain open-source when deployed as a service.
The Stop hook no longer says goodbye when a session ends. Farewell messages were a side-effect of the post-mortem enforcement hook, creating confusing output on every session close.
Stop hook no longer says goodbye when session ends. The farewell was an unintended side-effect of the post-mortem enforcement block — removed cleanly without affecting diary write behavior.
The Stop hook now uses decision:block instead of approve to enforce post-mortem execution. This ensures the session diary is always written before Claude exits — no more lost context on abrupt stops.
Stop hook changed from approve to decision:block so post-mortem writing is enforced architecturally, not just suggested.
Fixed infinite block loop triggered when the Stop hook blocked its own post-mortem execution. Added trivial session detection to skip diary write on empty or no-op sessions.
Long sessions no longer lose their thread. NEXO preserves session context across Claude Code compaction events using PreCompact checkpoints and PostCompact re-injection. 8-hour sessions feel like one continuous conversation.
Before compaction, NEXO saves a complete snapshot to SQLite: current task, active files, decisions, errors, reasoning thread, and next step.
After compaction, a structured block is re-injected into context with everything needed to continue seamlessly. Zero "where were we?" moments.
The checkpoint updates automatically every interaction via the heartbeat. No manual action required — continuity is always maintained.
The agent thinks before acting. Architectural inhibitory control validates reasoning quality and physically restricts tools until the plan is sound. Designed via 3-way AI debate (Claude Opus + GPT-5.4 + Gemini 3.1 Pro).
Unknowns detected. Tools restricted to read and search. Agent must gather information before proceeding.
No plan or verification step. Agent can propose but not execute. User reviews before action.
Plan, evidence, and verification present. Full tool access granted. Agent executes with confidence.
v0.10.0 tackles the "stores but forgets" problem. Three new features ensure the right memories surface at the right time — at session boot, during conversation, and when delegating to subagents.
Pre-loads relevant memories at session boot by composing a query from pending followups, due reminders, and last session's topics. No more cold starts.
Bundles all area knowledge (learnings, changes, followups, preferences, cognitive memories) into a single injectable packet for subagent delegation.
Heartbeat detects project keywords in conversation and automatically surfaces relevant learnings. Context arrives proactively — no manual query needed.
Quarantine queue now processes automatically during the nightly cycle. Items are promoted, rejected, or expired based on policy — no manual intervention needed.
Corrections and critical learnings are auto-pinned at ingest. Pinned memories never decay and get a +0.2 boost in search results. User corrections stick permanently.
Dream insights (cross-memory connections) are excluded from default search, reducing noise by 21%. Capped at 50 active insights; excess is archived automatically.
v0.9.0 introduces permanent subconscious memory. Session diaries are now archived forever before cleanup — nothing is ever truly lost. Plus fuzzy credential search for when you can't remember the exact service name.
Session diaries older than 180 days are moved to a permanent diary_archive table instead of being deleted. Search by text, domain, year, or month. nexo_recall automatically falls back to the archive when recent memory has few results.
When exact credential match fails, NEXO searches across service, key, and notes fields. Results are tagged as fuzzy matches so you know they're suggestions, not exact hits.
nexo_recall now has a two-tier search: recent memory first, then diary archive fallback. Your agent never truly forgets — old context surfaces when needed.
v0.8.10 gives your AI agent a relationship graph, a visual brain dashboard, and runs everywhere. 988 bi-temporal nodes with D3 visualization, 6 dashboard pages, and full Linux + Windows support.
Bi-temporal entity-relationship graph with 988 nodes and 896 edges. BFS traversal discovers multi-hop connections. Event-sourced edges with smart dedup (ADD/UPDATE/NOOP). Temporal queries. Interactive D3.js visualization.
Visual interface at localhost:6174 with 6 pages: Overview, Graph, Memory, Somatic, Adaptive, Sessions. FastAPI + D3.js. See your AI brain in real time.
Full Linux and Windows support. Platform-appropriate process managers. Opportunistic maintenance when resources are available.
Generates a full briefing from SQLite: overdue reminders, today's tasks, pending followups, active sessions. Cached for 1 hour.
Mandatory self-critique with 5 questions, session buffer, followup creation, proactive seeds for next session, and reflection trigger.
Saves context before conversation compression. Prevents losing the thread — compaction without a diary means starting from zero.
Captures meaningful tool usage to the Sensory Register. Feeds the Atkinson-Shiffrin memory pipeline silently.
After 3+ sessions, processes the buffer: extracts recurring tasks, error patterns, mood trends. Updates user model. No LLM needed.
Hardwired behavioral foundation: never promise without scheduling, verify before claiming done, audit before delivering, proactive not reactive.
5 configurable axes: autonomy, communication style, honesty level, proactivity, error handling. Set during install, adjustable anytime.
Seamless upgrade from previous versions. Updates hooks, core files, plugins, scripts — never touches your data or customized CLAUDE.md.
Open source, AGPL-3.0 licensed, and built for builders who want their AI to actually remember.