nexo-brain 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "nexo-brain",
3
+ "version": "2.5.1",
4
+ "description": "Cognitive co-operator — persistent memory, learning, autonomous processes, Deep Sleep overnight analysis, unified diagnostics, executable skills, day orchestrator, and web dashboard for AI agents.",
5
+ "author": {
6
+ "name": "NEXO Brain",
7
+ "email": "info@nexo-brain.com",
8
+ "url": "https://nexo-brain.com"
9
+ },
10
+ "homepage": "https://nexo-brain.com",
11
+ "repository": "https://github.com/wazionapps/nexo",
12
+ "license": "AGPL-3.0",
13
+ "keywords": [
14
+ "memory",
15
+ "cognitive",
16
+ "autonomous",
17
+ "deep-sleep",
18
+ "learning",
19
+ "mcp",
20
+ "work-continuity",
21
+ "skills",
22
+ "doctor",
23
+ "dashboard"
24
+ ],
25
+ "mcpServers": "./.mcp.json",
26
+ "hooks": "./hooks/hooks.json",
27
+ "userConfig": {
28
+ "operator_name": {
29
+ "description": "What should your AI co-operator call itself? (default: NEXO)",
30
+ "sensitive": false
31
+ }
32
+ }
33
+ }
package/.mcp.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "nexo": {
4
+ "command": "${CLAUDE_PLUGIN_DATA}/.venv/bin/python3",
5
+ "args": ["${CLAUDE_PLUGIN_ROOT}/src/server.py"],
6
+ "env": {
7
+ "NEXO_HOME": "${CLAUDE_PLUGIN_DATA}",
8
+ "NEXO_CODE": "${CLAUDE_PLUGIN_ROOT}/src"
9
+ }
10
+ }
11
+ }
12
+ }
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![GitHub stars](https://img.shields.io/github/stars/wazionapps/nexo?style=social)](https://github.com/wazionapps/nexo/stargazers)
7
7
  [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
8
8
 
9
- > The first AI memory system with architectural inhibitory control — the agent reasons about whether to act before acting. Cognitive Cortex, Context Continuity via auto-compaction hooks, Smart Startup, Context Packets, Auto-Prime, 30 Core Rules as DNA, auto-update, auto-diary, and CLAUDE.md version tracker. Battle-tested from 6 months of production use, validated via multi-AI debate.
9
+ > The first AI memory system with architectural inhibitory control — the agent reasons about whether to act before acting. Cognitive Cortex, Context Continuity via auto-compaction hooks, Smart Startup, Context Packets, Auto-Prime, 30 Core Rules as DNA, auto-update, auto-diary, CLAUDE.md version tracker, personal scripts registry, and Claude Code plugin structure. Battle-tested from 6 months of production use, validated via multi-AI debate.
10
10
 
11
11
  **NEXO Brain transforms any MCP-compatible AI agent from a stateless assistant into a cognitive partner that remembers, learns, forgets, adapts, and builds a relationship with you over time.**
12
12
 
@@ -198,7 +198,7 @@ This means long sessions (8+ hours) feel like one continuous conversation instea
198
198
 
199
199
  ## Cognitive Features
200
200
 
201
- NEXO Brain provides **147+ MCP tools** across 20+ categories. These features implement cognitive science concepts that go beyond basic memory:
201
+ NEXO Brain provides **144+ MCP tools** across 20+ categories. These features implement cognitive science concepts that go beyond basic memory:
202
202
 
203
203
  ### Input Pipeline
204
204
 
@@ -269,7 +269,7 @@ Full results in [`benchmarks/locomo/results/`](benchmarks/locomo/results/).
269
269
 
270
270
  ## Nervous System (v2.0.0)
271
271
 
272
- NEXO Brain doesn't just respond — it runs 15 autonomous processes in the background, like a biological nervous system. They handle maintenance, health monitoring, and self-improvement without any user interaction:
272
+ NEXO Brain doesn't just respond — it runs 14 autonomous processes in the background, like a biological nervous system. They handle maintenance, health monitoring, and self-improvement without any user interaction:
273
273
 
274
274
  | Script | Schedule | What It Does |
275
275
  |--------|----------|-------------|
@@ -289,7 +289,7 @@ NEXO Brain doesn't just respond — it runs 15 autonomous processes in the backg
289
289
  | **watchdog** | Every 30 min | Monitors services, LaunchAgents, and infrastructure health |
290
290
  | **auto-close-sessions** | Every 5 min | Cleans stale sessions |
291
291
 
292
- Core processes are defined in `src/crons/manifest.json` and auto-synced to your system by `nexo_update`. On macOS they run via LaunchAgents; on Linux via systemd user timers. `tcc-approve`, `prevent-sleep`, and `backup` are platform/personal helpers — not in the manifest but listed above for completeness. Personal crons (your own scripts) are never touched by the sync. If your Mac was asleep during a scheduled process, the catch-up script re-runs everything in order when it wakes.
292
+ Core processes are defined in `src/crons/manifest.json` and auto-synced to your system by `nexo_update`. On macOS they run via LaunchAgents; on Linux via systemd user timers. `tcc-approve`, `prevent-sleep`, and `backup` are platform/personal helpers — not in the manifest but listed above for completeness. Personal scripts (your own automations) are tracked separately in the Personal Scripts Registry and never touched by the core sync. If your Mac was asleep during a scheduled process, the catch-up script re-runs everything in order when it wakes.
293
293
 
294
294
  ## Deep Sleep v2 — Overnight Learning (v2.1.0)
295
295
 
@@ -390,7 +390,7 @@ This opens `localhost:6174` in your browser. Add `--port 8080` to change the por
390
390
 
391
391
  ## Full Orchestration System
392
392
 
393
- Memory alone doesn't make a co-operator. What makes the difference is the **behavioral loop** — the automated discipline that ensures every session starts informed, runs with guardrails, and ends with self-reflection.
393
+ Memory alone doesn't make a co-operator. What makes the difference is the **behavioral loop** — the automated discipline that ensures every session starts informed, runs with guardrails, and ends with self-reflection. The hooks and lifecycle below are built into the core product. The optional Day Orchestrator (autonomous headless cycles) was removed from core in v2.6.0 — power users can set it up as a personal script.
394
394
 
395
395
  ### Automated Hooks
396
396
 
@@ -501,7 +501,7 @@ The installer handles everything:
501
501
  - Node.js project detected
502
502
  Configuring MCP server...
503
503
  Setting up nervous system...
504
- 15 autonomous processes configured.
504
+ 14 autonomous processes configured.
505
505
  Dashboard configured at localhost:6174.
506
506
  Caffeinate enabled.
507
507
  Generating operator instructions...
@@ -532,23 +532,31 @@ That's it. No need to run `claude` manually. Your operator will greet you immedi
532
532
  | Component | What | Where |
533
533
  |-----------|------|-------|
534
534
  | Cognitive engine | Python: fastembed, numpy, vector search | pip packages |
535
- | MCP server | 147+ tools for memory, cognition, learning, guard | NEXO_HOME/ |
535
+ | MCP server | 144+ tools for memory, cognition, learning, guard | NEXO_HOME/ |
536
536
  | Plugins | Guard, episodic memory, cognitive memory, entities, preferences, update, etc. | Code: src/plugins/, Personal: NEXO_HOME/plugins/ |
537
537
  | Hooks (7) | SessionStart, Stop, PostToolUse, PreCompact, PostCompact | NEXO_HOME/hooks/ |
538
- | Nervous system | 15 autonomous processes (decay, sleep, audit, evolution, watchdog, etc.) | NEXO_HOME/scripts/ |
539
- | Dashboard | Web UI at localhost:6174 (6 pages) | NEXO_HOME/dashboard/ |
538
+ | Nervous system | 14 autonomous processes (decay, sleep, audit, evolution, watchdog, dashboard, etc.) | NEXO_HOME/scripts/ |
539
+ | Dashboard | Web UI at localhost:6174 (23 modules, dark theme) — opt-in, always-on | NEXO_HOME/dashboard/ |
540
+ | Runtime CLI | `nexo` command: chat, scripts, doctor, skills, update | NEXO_HOME/bin/ |
541
+ | Doctor | Unified diagnostics: boot/runtime/deep tiers, `--fix` mode | src/doctor/ |
542
+ | Skills v2 | Executable skills with guide/execute/hybrid modes, approval levels | NEXO_HOME/skills/ |
543
+ | Personal Scripts Registry | User-defined scripts tracked in SQLite with scheduling, reconciliation, and 9 MCP tools | NEXO_HOME/scripts/ |
540
544
  | CLAUDE.md | Complete operator instructions (Codex, hooks, guard, trust, memory) | ~/.claude/CLAUDE.md |
541
545
  | Schedule config | schedule.json with customizable process times and timezone | NEXO_HOME/config/ |
542
546
  | Auto-update | Non-blocking startup check (5s max), opt-out via schedule.json | Built into server startup |
543
547
  | CLAUDE.md tracker | Version-tracked core sections with safe updates preserving customizations | Built into auto-update |
544
548
  | Auto-diary | 3-layer system: PostToolUse every 10 calls, PreCompact emergency, heartbeat DIARY_OVERDUE | Built into hooks |
545
- | Claude Code config | MCP server + 7 hooks + 15 processes registered | ~/.claude/settings.json |
549
+ | Claude Code config | MCP server + 7 hooks + core processes registered | ~/.claude/settings.json |
546
550
 
547
551
  ### Runtime CLI
548
552
 
549
553
  After installation or auto-update, NEXO adds `NEXO_HOME/bin` to your shell `PATH`. Open a new terminal and the `nexo` command provides operational tools:
550
554
 
551
555
  ```bash
556
+ # Claude Code
557
+ nexo chat # Launch Claude Code in the current directory
558
+ nexo chat ~/claude # Launch Claude Code in a specific directory
559
+
552
560
  # Personal Scripts
553
561
  nexo scripts list # List your personal scripts
554
562
  nexo scripts run my-script # Run a script with injected NEXO env
@@ -570,7 +578,7 @@ nexo doctor --tier runtime --json # Machine-readable health report
570
578
  nexo doctor --fix # Apply deterministic repairs
571
579
  ```
572
580
 
573
- Personal scripts live in `NEXO_HOME/scripts/` with inline metadata. See `docs/writing-scripts.md` for details.
581
+ Personal scripts live in `NEXO_HOME/scripts/` with inline metadata and are tracked in a first-class registry (SQLite). 9 MCP tools manage the full lifecycle: `nexo_personal_scripts_list`, `nexo_personal_script_create`, `nexo_personal_script_remove`, `nexo_personal_scripts_reconcile`, `nexo_personal_scripts_sync`, `nexo_personal_scripts_classify`, `nexo_personal_script_schedules`, `nexo_personal_script_unschedule`, `nexo_personal_scripts_ensure_schedules`. See `docs/writing-scripts.md` for details.
574
582
 
575
583
  Skills v2 combine procedural guides with optional executable scripts. Personal skills live in `NEXO_HOME/skills/`, packaged core skills live in `NEXO_CODE/skills/` during development and `NEXO_HOME/skills-core/` in installed environments, and staged runtime copies live in `NEXO_HOME/skills-runtime/`. Execution is fully autonomous: Deep Sleep can evolve mature guide skills into executable drafts automatically, and runtime execution no longer waits for manual approval. See `docs/skills-v2.md` for the full model.
576
584
 
@@ -580,7 +588,7 @@ The Doctor system reads existing health artifacts (immune, watchdog, self-audit)
580
588
 
581
589
  - **macOS or Linux** (Windows via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install))
582
590
  - **Node.js 18+** (for the installer)
583
- - **Claude Opus (latest version) strongly recommended.** NEXO Brain provides 147+ MCP tools across 20+ categories. This cognitive load requires a top-tier model with large context window. Smaller models (Haiku, Sonnet) may struggle with tool selection and produce inconsistent results. Opus handles all 147+ tools without hesitation.
591
+ - **Claude Opus (latest version) strongly recommended.** NEXO Brain provides 144+ MCP tools across 20+ categories. This cognitive load requires a top-tier model with large context window. Smaller models (Haiku, Sonnet) may struggle with tool selection and produce inconsistent results. Opus handles all 144+ tools without hesitation.
584
592
  - Python 3, Homebrew, and Claude Code are installed automatically if missing.
585
593
 
586
594
  ## Architecture
@@ -599,7 +607,7 @@ NEXO Brain separates **code** (immutable, in the repo or npm package) from **dat
599
607
 
600
608
  The plugin loader scans `src/plugins/` first (base), then `NEXO_HOME/plugins/` (personal override by filename). This dual-directory approach lets you extend NEXO without forking the repo.
601
609
 
602
- ### 147+ MCP Tools across 20+ Categories
610
+ ### 144+ MCP Tools across 20+ Categories
603
611
 
604
612
  | Category | Count | Tools | Purpose |
605
613
  |----------|-------|-------|---------|
@@ -624,6 +632,7 @@ The plugin loader scans `src/plugins/` first (base), then `NEXO_HOME/plugins/` (
624
632
  | Adaptive & Somatic | 4 | adaptive_weights, adaptive_override, somatic_check, somatic_stats | Learned signal weights + pain memory per file |
625
633
  | Knowledge Graph | 4 | kg_query, kg_path, kg_neighbors, kg_stats | Bi-temporal entity-relationship graph |
626
634
  | Context Continuity | 2 | checkpoint_save, checkpoint_read | Auto-compaction session preservation |
635
+ | Personal Scripts | 9 | personal_scripts_list, personal_script_create, personal_script_remove, personal_scripts_reconcile, personal_scripts_sync, personal_scripts_classify, personal_script_schedules, personal_script_unschedule, personal_scripts_ensure_schedules | First-class script registry with lifecycle, scheduling, and reconciliation |
627
636
  | Update | 1 | update | Pull latest code, backup, migrate, verify (with rollback) |
628
637
 
629
638
  ### Plugin System
@@ -682,7 +691,7 @@ NEXO Brain is designed as an MCP server. Claude Code is the primary supported cl
682
691
  npx nexo-brain
683
692
  ```
684
693
 
685
- All 147+ tools are available immediately after installation. The installer configures Claude Code's `~/.claude/settings.json` automatically.
694
+ All 144+ tools are available immediately after installation. The installer configures Claude Code's `~/.claude/settings.json` automatically.
686
695
 
687
696
  ### OpenClaw
688
697
 
@@ -778,17 +787,33 @@ If NEXO Brain is useful to you, consider:
778
787
 
779
788
  [![Star History Chart](https://api.star-history.com/svg?repos=wazionapps/nexo&type=Date)](https://star-history.com/#wazionapps/nexo&Date)
780
789
 
781
- ## Known Issues (v2.0.0)
790
+ ## Known Issues
782
791
 
783
- | Priority | Issue | Planned |
784
- |----------|-------|---------|
785
- | P0 | Credentials stored in plaintext SQLite — protect with filesystem permissions | v2.1.0 |
786
- | P0 | Shell hooks use SQL string interpolation (injection risk) | v2.1.0 |
787
- | P0 | Dashboard has no authentication (localhost only) | v2.1.0 |
788
- | P0 | Database migrations are fail-open (errors logged but not blocking) | v2.1.0 |
792
+ | Priority | Issue | Status |
793
+ |----------|-------|--------|
794
+ | P1 | Credentials stored in plaintext SQLite — protect with filesystem permissions | Mitigated: secret redaction in tool logs (v2.4.0) |
795
+ | P2 | Dashboard has no authentication (localhost only) | By design — bind to localhost, no remote access |
789
796
 
790
797
  ## Changelog
791
798
 
799
+ ### v2.6.0 — Personal Scripts Registry, Plugin Marketplace, Orchestrator Decoupled (2026-04-03)
800
+ - **Personal Scripts Registry**: First-class script tracking in SQLite with 9 MCP tools for full lifecycle management — create, list, remove, schedule, unschedule, reconcile, sync, classify.
801
+ - **Orchestrator removed from core**: Day Orchestrator decoupled from the product. Power users keep it as a personal script. Reduces complexity for standard installs.
802
+ - **Claude Code plugin structure**: `plugin.json` + entry point for Anthropic marketplace submission.
803
+ - **`nexo chat`**: Official CLI command to launch Claude Code with NEXO as operator.
804
+ - **Managed Evolution hardening**: Can now modify core behavior modules with rollback followups. Fixed false-positive watchdog tamper detection.
805
+ - **Cron reliability**: Hardened recovery, TCC diagnostics, keepalive sync, disabled optional cron respect.
806
+ - **Duplicate learning prevention**: Exact-title guard before insert.
807
+
808
+ ### v2.5.0 — Runtime CLI, Doctor, Skills v2, Day Orchestrator (2026-04-03)
809
+ - **Runtime CLI** (`nexo`): New operational CLI separate from installer. `nexo scripts list/run/doctor/call` for personal scripts, `nexo doctor` for diagnostics, `nexo skills apply` for executable skills, `nexo update` for one-step sync.
810
+ - **Unified Doctor**: Modular diagnostic system with boot/runtime/deep tiers. Report-only by default, deterministic `--fix` mode. MCP tool `nexo_doctor`. LaunchAgent schedule drift detection and reconciliation.
811
+ - **Skills v2**: Executable skills with guide/execute/hybrid modes. Security levels (read-only/local/remote) with explicit approval. Core vs personal vs community directories. Deep Sleep auto-evolution integration.
812
+ - **Day Orchestrator**: Autonomous NEXO cycles every 15 min (8:00-23:00). *(Removed from core in v2.6.0 — available as personal script.)*
813
+ - **Dashboard always-on**: Web UI at localhost:6174 as persistent LaunchAgent. 23 modules, Jinja2 templating, dark theme. Opt-in.
814
+ - **Personal Scripts Framework**: Auto-discovery in NEXO_HOME/scripts/, inline metadata, runtime detection, forbidden-pattern validation. *(Promoted to first-class registry in v2.6.0.)*
815
+ - Configurable operator name (UserContext singleton), watchdog normalized to 30 min, LaunchAgent drift fix.
816
+
792
817
  ### v2.4.0 — Skills, Cron Scheduler, Security, Full Audit (2026-04-03)
793
818
  - **Skill Auto-Creation**: Deep Sleep extracts reusable procedures from sessions. Content stored as markdown with steps and gotchas. Trust pipeline with autonomous quality control.
794
819
  - **Cron Scheduler**: execution tracking (`cron_runs` table), `nexo_schedule_status` and `nexo_schedule_add` MCP tools, universal cron wrapper for all processes.
@@ -811,9 +836,9 @@ If NEXO Brain is useful to you, consider:
811
836
  - **Auto-diary**: 3-layer system — PostToolUse every 10 calls, PreCompact emergency save, heartbeat DIARY_OVERDUE signal.
812
837
  - **CLAUDE.md version tracker**: Section markers enable safe core updates without losing user customizations.
813
838
  - **schedule.json**: Customizable process schedules with timezone support and `auto_update` flag.
814
- - **15 autonomous processes**: Added auto-close-sessions, synthesis, backup, tcc-approve, prevent-sleep (cross-platform).
839
+ - **14 autonomous processes**: Added auto-close-sessions, synthesis, backup, tcc-approve, prevent-sleep (cross-platform).
815
840
  - **7 hooks**: SessionStart (timestamp + briefing), Stop, PostToolUse (capture + inbox), PreCompact, PostCompact.
816
- - **147+ MCP tools**: Added `nexo_update` tool for manual updates with rollback.
841
+ - **144+ MCP tools**: Added `nexo_update` tool for manual updates with rollback.
817
842
  - **Lambda fix**: Decay values were 24x too aggressive (STM: 7h to 7d, LTM: 2.4d to 60d).
818
843
  - **Guard scoping**: Was returning 35+ irrelevant blocking rules; now scoped to area and gated to high/critical.
819
844
  - **12 rounds of external audit**: ~60 findings resolved.
package/bin/nexo-brain.js CHANGED
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  const { execSync, spawnSync } = require("child_process");
18
+ const crypto = require("crypto");
18
19
  const fs = require("fs");
19
20
  const path = require("path");
20
21
  const readline = require("readline");
@@ -59,13 +60,67 @@ function log(msg) {
59
60
  console.log(` ${msg}`);
60
61
  }
61
62
 
63
+ function syncWatchdogHashRegistry(nexoHome) {
64
+ try {
65
+ const watchdogPath = path.join(nexoHome, "scripts", "nexo-watchdog.sh");
66
+ if (!fs.existsSync(watchdogPath)) return;
67
+
68
+ const registryPath = path.join(nexoHome, "scripts", ".watchdog-hashes");
69
+ const entries = new Map();
70
+ if (fs.existsSync(registryPath)) {
71
+ for (const line of fs.readFileSync(registryPath, "utf8").split(/\r?\n/)) {
72
+ if (!line.includes("|")) continue;
73
+ const [filePath, expectedHash] = line.split("|");
74
+ if (filePath) entries.set(filePath, expectedHash || "");
75
+ }
76
+ }
77
+
78
+ const digest = crypto.createHash("sha256").update(fs.readFileSync(watchdogPath)).digest("hex");
79
+ entries.set(watchdogPath, digest);
80
+ const body = Array.from(entries.entries())
81
+ .sort(([a], [b]) => a.localeCompare(b))
82
+ .map(([filePath, hash]) => `${filePath}|${hash}`)
83
+ .join("\n");
84
+ fs.writeFileSync(registryPath, `${body}\n`);
85
+ } catch (err) {
86
+ log(`WARN: could not sync watchdog hash registry: ${err.message}`);
87
+ }
88
+ }
89
+
90
+ function isProtectedMacPath(candidate) {
91
+ if (process.platform !== "darwin" || !candidate) return false;
92
+ const homeDir = require("os").homedir();
93
+ const expanded = candidate.replace(/^~/, homeDir);
94
+ const resolved = path.resolve(expanded);
95
+ const protectedRoots = [
96
+ path.join(homeDir, "Documents"),
97
+ path.join(homeDir, "Desktop"),
98
+ path.join(homeDir, "Downloads"),
99
+ path.join(homeDir, "Library", "Mobile Documents"),
100
+ ];
101
+ return protectedRoots.some((root) => resolved === root || resolved.startsWith(`${root}${path.sep}`));
102
+ }
103
+
104
+ function logMacPermissionsNotice(nexoHome, pythonPath = "") {
105
+ if (!isProtectedMacPath(nexoHome)) return;
106
+ log("macOS protected-folder warning:");
107
+ log(` NEXO_HOME is inside a protected folder: ${nexoHome}`);
108
+ log(" Background jobs may fail with 'Operation not permitted'.");
109
+ log(" Recommended: move NEXO_HOME outside Documents/Desktop/Downloads/iCloud Drive.");
110
+ log(" If you keep it there, grant Full Disk Access to /bin/bash and your Python runtime.");
111
+ if (pythonPath) {
112
+ log(` Python runtime: ${pythonPath}`);
113
+ }
114
+ log(" System Settings → Privacy & Security → Full Disk Access");
115
+ }
116
+
62
117
  // ══════════════════════════════════════════════════════════════════════════════
63
118
  // CORE PROCESS & HOOK DEFINITIONS
64
- // All 13 nightly/periodic processes and all 8 core hooks that make NEXO functional.
119
+ // All core nightly/periodic processes and all 8 core hooks that make NEXO functional.
65
120
  // ══════════════════════════════════════════════════════════════════════════════
66
121
 
67
122
  /**
68
- * Complete definition of all 13 NEXO automated processes.
123
+ * Complete definition of all core NEXO automated processes.
69
124
  * Each entry specifies the script, its interpreter ("python" or "bash"),
70
125
  * the schedule type, and default schedule values.
71
126
  */
@@ -95,8 +150,6 @@ const ALL_PROCESSES = [
95
150
  type: "keepAlive", purpose: "Keep machine awake for nocturnal processes" },
96
151
  { name: "dashboard", script: "nexo-dashboard.sh", interpreter: "bash", scriptDir: "scripts",
97
152
  type: "keepAlive", optional: "dashboard", purpose: "Web dashboard at localhost:6174" },
98
- { name: "day-orchestrator", script: "nexo-day-orchestrator.sh", interpreter: "bash", scriptDir: "scripts",
99
- type: "keepAlive", optional: "orchestrator", purpose: "Autonomous NEXO cycles every 15 min (8:00-23:00)" },
100
153
  // --- Daily (times from schedule.json) ---
101
154
  { name: "cognitive-decay", script: "nexo-cognitive-decay.py", interpreter: "python", scriptDir: "scripts",
102
155
  type: "daily", defaultHour: 3, defaultMinute: 0, purpose: "Memory decay" },
@@ -741,7 +794,7 @@ async function main() {
741
794
  fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
742
795
  log(" All 8 core hooks registered in Claude Code settings.");
743
796
 
744
- // Regenerate ALL 13 LaunchAgents / systemd timers
797
+ // Regenerate all core LaunchAgents / systemd timers
745
798
  const migSchedule = loadOrCreateSchedule(NEXO_HOME);
746
799
  const migPython = findVenvPython(NEXO_HOME) || "python3";
747
800
  let migOptionals = {};
@@ -865,6 +918,8 @@ async function main() {
865
918
  });
866
919
  }
867
920
 
921
+ logMacPermissionsNotice(NEXO_HOME, syncPython);
922
+
868
923
  log(`Already at v${currentVersion}. No migration needed.`);
869
924
  rl.close();
870
925
  return;
@@ -909,6 +964,7 @@ async function main() {
909
964
  }
910
965
  const pyVersion = run(`${python} --version`);
911
966
  log(`Found ${pyVersion} at ${python}`);
967
+ logMacPermissionsNotice(NEXO_HOME, python);
912
968
 
913
969
  // Find or install Claude Code
914
970
  let claudeInstalled = run("which claude");
@@ -972,9 +1028,6 @@ async function main() {
972
1028
  dashboardQ: " Enable web dashboard at localhost:6174?\n (Always-on UI to explore memory, sessions, learnings, and system health)\n 1. Yes\n 2. No\n > ",
973
1029
  dashYes: "Dashboard enabled.",
974
1030
  dashNo: "Dashboard disabled. You can start it manually: nexo dashboard",
975
- orchestratorQ: " Enable autonomous mode? (I'll work on my own every 15 min: check followups, emails, infra, and report by email)\n 1. Yes\n 2. No\n > ",
976
- orchYes: "Autonomous mode enabled. I'll be working for you 8:00-23:00.",
977
- orchNo: "Autonomous mode disabled. I'll only work when you open a session.",
978
1031
  autoInstallQ: " Can I install tools automatically if I need them? (brew, pip, npm)\n 1. Yes, install whatever you need\n 2. Ask me before installing anything\n > ",
979
1032
  autoInstallYes: "Auto-install enabled.",
980
1033
  autoInstallNo: "I'll ask before installing.",
@@ -1007,9 +1060,6 @@ async function main() {
1007
1060
  dashboardQ: " ¿Activar el dashboard web en localhost:6174?\n (UI siempre activa para explorar memoria, sesiones, learnings y salud del sistema)\n 1. Sí\n 2. No\n > ",
1008
1061
  dashYes: "Dashboard activado.",
1009
1062
  dashNo: "Dashboard desactivado. Puedes iniciarlo manualmente: nexo dashboard",
1010
- orchestratorQ: " ¿Activar modo autónomo? (Trabajo solo cada 15 min: reviso followups, emails, infra, y te informo por email)\n 1. Sí\n 2. No\n > ",
1011
- orchYes: "Modo autónomo activado. Estaré trabajando para ti de 8:00 a 23:00.",
1012
- orchNo: "Modo autónomo desactivado. Solo trabajo cuando abras sesión.",
1013
1063
  autoInstallQ: " ¿Puedo instalar herramientas automáticamente si las necesito? (brew, pip, npm)\n 1. Sí, instala lo que necesites\n 2. Pregúntame antes de instalar algo\n > ",
1014
1064
  autoInstallYes: "Auto-instalación activada.",
1015
1065
  autoInstallNo: "Te preguntaré antes.",
@@ -1042,9 +1092,6 @@ async function main() {
1042
1092
  dashboardQ: " Activer le dashboard web sur localhost:6174 ?\n (UI toujours active pour explorer mémoire, sessions et santé du système)\n 1. Oui\n 2. Non\n > ",
1043
1093
  dashYes: "Dashboard activé.",
1044
1094
  dashNo: "Dashboard désactivé. Démarrage manuel : nexo dashboard",
1045
- orchestratorQ: " Activer le mode autonome ? (Je travaille seul toutes les 15 min : followups, emails, infra, rapport par email)\n 1. Oui\n 2. Non\n > ",
1046
- orchYes: "Mode autonome activé. Je travaille pour vous de 8h à 23h.",
1047
- orchNo: "Mode autonome désactivé. Je travaille uniquement en session.",
1048
1095
  autoInstallQ: " Puis-je installer des outils automatiquement ? (brew, pip, npm)\n 1. Oui\n 2. Demande-moi avant\n > ",
1049
1096
  autoInstallYes: "Auto-installation activée.",
1050
1097
  autoInstallNo: "Je demanderai avant.",
@@ -1077,9 +1124,6 @@ async function main() {
1077
1124
  dashboardQ: " Web-Dashboard auf localhost:6174 aktivieren?\n (Immer aktive UI für Speicher, Sitzungen und Systemgesundheit)\n 1. Ja\n 2. Nein\n > ",
1078
1125
  dashYes: "Dashboard aktiviert.",
1079
1126
  dashNo: "Dashboard deaktiviert. Manuell starten: nexo dashboard",
1080
- orchestratorQ: " Autonomen Modus aktivieren? (Ich arbeite alle 15 Min selbstständig: Followups, E-Mails, Infra, Bericht per E-Mail)\n 1. Ja\n 2. Nein\n > ",
1081
- orchYes: "Autonomer Modus aktiviert. Ich arbeite für dich von 8:00 bis 23:00.",
1082
- orchNo: "Autonomer Modus deaktiviert. Ich arbeite nur in Sitzungen.",
1083
1127
  autoInstallQ: " Darf ich Tools automatisch installieren? (brew, pip, npm)\n 1. Ja\n 2. Frag mich vorher\n > ",
1084
1128
  autoInstallYes: "Auto-Installation aktiviert.",
1085
1129
  autoInstallNo: "Frage vorher.",
@@ -1112,9 +1156,6 @@ async function main() {
1112
1156
  dashboardQ: " Attivare la dashboard web su localhost:6174?\n (UI sempre attiva per esplorare memoria, sessioni e salute del sistema)\n 1. Sì\n 2. No\n > ",
1113
1157
  dashYes: "Dashboard attivata.",
1114
1158
  dashNo: "Dashboard disattivata. Avvio manuale: nexo dashboard",
1115
- orchestratorQ: " Attivare la modalità autonoma? (Lavoro da solo ogni 15 min: followup, email, infra, report via email)\n 1. Sì\n 2. No\n > ",
1116
- orchYes: "Modalità autonoma attivata. Lavoro per te dalle 8:00 alle 23:00.",
1117
- orchNo: "Modalità autonoma disattivata. Lavoro solo nelle sessioni.",
1118
1159
  autoInstallQ: " Posso installare strumenti automaticamente? (brew, pip, npm)\n 1. Sì\n 2. Chiedimi prima\n > ",
1119
1160
  autoInstallYes: "Auto-installazione attivata.",
1120
1161
  autoInstallNo: "Chiederò prima.",
@@ -1147,9 +1188,6 @@ async function main() {
1147
1188
  dashboardQ: " Ativar dashboard web em localhost:6174?\n (UI sempre ativa para explorar memória, sessões e saúde do sistema)\n 1. Sim\n 2. Não\n > ",
1148
1189
  dashYes: "Dashboard ativado.",
1149
1190
  dashNo: "Dashboard desativado. Iniciar manualmente: nexo dashboard",
1150
- orchestratorQ: " Ativar modo autônomo? (Trabalho sozinho a cada 15 min: followups, emails, infra, relatório por email)\n 1. Sim\n 2. Não\n > ",
1151
- orchYes: "Modo autônomo ativado. Trabalho para você das 8:00 às 23:00.",
1152
- orchNo: "Modo autônomo desativado. Trabalho apenas nas sessões.",
1153
1191
  autoInstallQ: " Posso instalar ferramentas automaticamente? (brew, pip, npm)\n 1. Sim\n 2. Pergunta antes\n > ",
1154
1192
  autoInstallYes: "Auto-instalação ativada.",
1155
1193
  autoInstallNo: "Perguntarei antes.",
@@ -1269,7 +1307,6 @@ async function main() {
1269
1307
  let doScan = false;
1270
1308
  let doCaffeinate = false;
1271
1309
  let doDashboard = false;
1272
- let doOrchestrator = false;
1273
1310
  let autoInstall = "ask";
1274
1311
  if (!useDefaults) {
1275
1312
  const scanAnswer = await ask(t.scanQ);
@@ -1290,12 +1327,6 @@ async function main() {
1290
1327
  log(doDashboard ? `✓ ${t.dashYes}` : t.dashNo);
1291
1328
  console.log("");
1292
1329
 
1293
- // Step 6c: Day Orchestrator — autonomous NEXO cycles
1294
- const orchAnswer = await ask(t.orchestratorQ);
1295
- doOrchestrator = orchAnswer.trim() === "1" || orchAnswer.trim().toLowerCase().startsWith("y") || orchAnswer.trim().toLowerCase().startsWith("s");
1296
- log(doOrchestrator ? `✓ ${t.orchYes}` : t.orchNo);
1297
- console.log("");
1298
-
1299
1330
  // Step 7: Auto-install permission (P11)
1300
1331
  const autoInstallAnswer = await ask(t.autoInstallQ);
1301
1332
  autoInstall = (autoInstallAnswer.trim() === "1" || autoInstallAnswer.trim().toLowerCase().startsWith("y") || autoInstallAnswer.trim().toLowerCase().startsWith("s")) ? "auto" : "ask";
@@ -1370,7 +1401,7 @@ async function main() {
1370
1401
  objective: "Improve operational excellence and reduce repeated errors",
1371
1402
  focus_areas: ["error_prevention", "proactivity", "memory_quality"],
1372
1403
  evolution_enabled: true,
1373
- evolution_mode: "review",
1404
+ evolution_mode: "auto",
1374
1405
  dimensions: {
1375
1406
  episodic_memory: { current: 0, target: 90 },
1376
1407
  autonomy: { current: 0, target: 80 },
@@ -1502,6 +1533,7 @@ async function main() {
1502
1533
  fs.readdirSync(scriptsDest).filter(f => f.endsWith(".sh")).forEach(f => {
1503
1534
  fs.chmodSync(path.join(scriptsDest, f), "755");
1504
1535
  });
1536
+ syncWatchdogHashRegistry(NEXO_HOME);
1505
1537
  }
1506
1538
 
1507
1539
  // Core skills are shipped separately from personal skills.
@@ -2033,10 +2065,10 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
2033
2065
  fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
2034
2066
  log("MCP server + 8 core hooks configured in Claude Code settings.");
2035
2067
 
2036
- // Step 7: Create schedule.json (only on fresh install) and install ALL 13 processes
2068
+ // Step 7: Create schedule.json (only on fresh install) and install core processes
2037
2069
  log("Setting up automated processes...");
2038
2070
  const schedule = loadOrCreateSchedule(NEXO_HOME);
2039
- const enabledOptionals = { dashboard: doDashboard, orchestrator: doOrchestrator };
2071
+ const enabledOptionals = { dashboard: doDashboard };
2040
2072
  if (isEphemeralInstall(NEXO_HOME)) {
2041
2073
  log("Ephemeral HOME/NEXO_HOME detected — skipping LaunchAgents installation.");
2042
2074
  } else {
@@ -0,0 +1,14 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/src/requirements.txt\" \"${CLAUDE_PLUGIN_DATA}/requirements.txt\" >/dev/null 2>&1 || (python3 -m venv \"${CLAUDE_PLUGIN_DATA}/.venv\" 2>/dev/null; cp \"${CLAUDE_PLUGIN_ROOT}/src/requirements.txt\" \"${CLAUDE_PLUGIN_DATA}/requirements.txt\"; \"${CLAUDE_PLUGIN_DATA}/.venv/bin/pip\" install --quiet -r \"${CLAUDE_PLUGIN_DATA}/requirements.txt\") || rm -f \"${CLAUDE_PLUGIN_DATA}/requirements.txt\""
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
- "description": "NEXO — Cognitive co-operator for Claude Code. Memory, emotional intelligence, overnight learning (Deep Sleep), cron management, trust scoring, and adaptive calibration.",
5
+ "description": "NEXO — Cognitive co-operator for Claude Code. Memory, emotional intelligence, overnight learning (Deep Sleep), personal scripts registry, cron management, trust scoring, managed evolution, and adaptive calibration.",
6
6
  "bin": {
7
7
  "nexo-brain": "./bin/nexo-brain.js",
8
8
  "nexo": "./bin/nexo.js"
@@ -39,7 +39,16 @@
39
39
  "cron-manifest",
40
40
  "session-tone",
41
41
  "mood-tracking",
42
- "productivity-analysis"
42
+ "productivity-analysis",
43
+ "runtime-cli",
44
+ "doctor",
45
+ "executable-skills",
46
+ "work-continuity",
47
+ "personal-scripts",
48
+ "script-registry",
49
+ "claude-code-plugin",
50
+ "managed-evolution",
51
+ "nexo-chat"
43
52
  ],
44
53
  "author": "NEXO Brain <info@nexo-brain.com>",
45
54
  "license": "AGPL-3.0",
@@ -63,6 +72,9 @@
63
72
  "!src/**/*.pyc",
64
73
  "!src/**/*.pyo",
65
74
  "templates/",
75
+ ".claude-plugin/",
76
+ ".mcp.json",
77
+ "hooks/hooks.json",
66
78
  "README.md",
67
79
  "LICENSE"
68
80
  ]
@@ -8,6 +8,7 @@ This is separate from plugins/update.py which handles MANUAL updates with rollba
8
8
  """
9
9
 
10
10
  import json
11
+ import hashlib
11
12
  import os
12
13
  import re
13
14
  import subprocess
@@ -56,6 +57,53 @@ def _write_last_check(data: dict):
56
57
  _log(f"Failed to write last-check file: {e}")
57
58
 
58
59
 
60
+ def _sync_watchdog_hash_registry():
61
+ """Keep the immutable-hash registry aligned with the installed watchdog script."""
62
+ try:
63
+ watchdog_file = NEXO_HOME / "scripts" / "nexo-watchdog.sh"
64
+ if not watchdog_file.exists():
65
+ return
66
+ registry_file = NEXO_HOME / "scripts" / ".watchdog-hashes"
67
+ entries: dict[str, str] = {}
68
+ if registry_file.exists():
69
+ for line in registry_file.read_text().splitlines():
70
+ if "|" not in line:
71
+ continue
72
+ filepath, expected = line.split("|", 1)
73
+ if filepath:
74
+ entries[filepath] = expected
75
+ actual_hash = hashlib.sha256(watchdog_file.read_bytes()).hexdigest()
76
+ entries[str(watchdog_file)] = actual_hash
77
+ registry_file.write_text(
78
+ "\n".join(f"{filepath}|{digest}" for filepath, digest in sorted(entries.items())) + "\n"
79
+ )
80
+ except Exception as e:
81
+ _log(f"watchdog hash registry sync error: {e}")
82
+
83
+
84
+ def _warn_protected_runtime_location():
85
+ """Log a targeted macOS TCC warning for risky NEXO_HOME locations."""
86
+ if sys.platform != "darwin":
87
+ return
88
+ try:
89
+ home = Path.home()
90
+ resolved = NEXO_HOME.resolve(strict=False)
91
+ protected_roots = (
92
+ home / "Documents",
93
+ home / "Desktop",
94
+ home / "Downloads",
95
+ home / "Library" / "Mobile Documents",
96
+ )
97
+ if any(resolved == root or root in resolved.parents for root in protected_roots):
98
+ _log(
99
+ "NEXO_HOME is inside a macOS protected folder. Background jobs may need Full Disk Access "
100
+ "for /bin/bash and the NEXO Python runtime, or NEXO_HOME should be moved outside "
101
+ "Documents/Desktop/Downloads/iCloud Drive."
102
+ )
103
+ except Exception as e:
104
+ _log(f"protected runtime warning skipped: {e}")
105
+
106
+
59
107
  def _is_git_repo() -> bool:
60
108
  """Check if REPO_DIR is inside a git repository."""
61
109
  try:
@@ -205,6 +253,24 @@ def _refresh_installed_manifest():
205
253
  _log(f"Manifest refresh warning: {e}")
206
254
 
207
255
 
256
+ def _cleanup_retired_runtime_files():
257
+ """Remove retired core files that should not survive updates."""
258
+ retired = [
259
+ NEXO_HOME / "scripts" / "nexo-day-orchestrator.sh",
260
+ ]
261
+ for target in retired:
262
+ try:
263
+ if target.exists():
264
+ if target.is_dir():
265
+ import shutil
266
+ shutil.rmtree(target)
267
+ else:
268
+ target.unlink()
269
+ _log(f"Removed retired runtime file: {target.name}")
270
+ except Exception as e:
271
+ _log(f"Retired runtime cleanup warning ({target.name}): {e}")
272
+
273
+
208
274
  def _sync_crons():
209
275
  """Sync cron definitions with manifest after a git pull."""
210
276
  try:
@@ -219,6 +285,7 @@ def _sync_crons():
219
285
  _log(f"Cron sync failed (exit {result.returncode}): {result.stderr or result.stdout}")
220
286
  return # Don't refresh manifest if timers weren't actually updated
221
287
  _log("Synced cron definitions with manifest")
288
+ _cleanup_retired_runtime_files()
222
289
  # Refresh the installed manifest only after successful sync
223
290
  _refresh_installed_manifest()
224
291
  except Exception as e:
@@ -811,13 +878,14 @@ def auto_update_check() -> dict:
811
878
  # Backfill evolution-objective.json for existing installs
812
879
  try:
813
880
  evo_obj_path = NEXO_HOME / "brain" / "evolution-objective.json"
881
+ from evolution_cycle import normalize_objective
814
882
  if not evo_obj_path.exists():
815
883
  (NEXO_HOME / "brain").mkdir(parents=True, exist_ok=True)
816
884
  default_objective = {
817
885
  "objective": "Improve operational excellence and reduce repeated errors",
818
886
  "focus_areas": ["error_prevention", "proactivity", "memory_quality"],
819
887
  "evolution_enabled": True,
820
- "evolution_mode": "review",
888
+ "evolution_mode": "auto",
821
889
  "dimensions": {
822
890
  "episodic_memory": {"current": 0, "target": 90},
823
891
  "autonomy": {"current": 0, "target": 80},
@@ -831,6 +899,12 @@ def auto_update_check() -> dict:
831
899
  }
832
900
  evo_obj_path.write_text(json.dumps(default_objective, indent=2))
833
901
  _log("Backfilled evolution-objective.json for existing install")
902
+ else:
903
+ raw_objective = json.loads(evo_obj_path.read_text())
904
+ normalized = normalize_objective(raw_objective)
905
+ if normalized != raw_objective:
906
+ evo_obj_path.write_text(json.dumps(normalized, indent=2, ensure_ascii=False))
907
+ _log("Normalized legacy evolution-objective.json")
834
908
  except Exception as e:
835
909
  _log(f"evolution-objective.json backfill error: {e}")
836
910
 
@@ -853,9 +927,12 @@ def auto_update_check() -> dict:
853
927
  except Exception as e:
854
928
  _log(f"scripts backfill error: {e}")
855
929
 
930
+ _sync_watchdog_hash_registry()
931
+ _warn_protected_runtime_location()
932
+
856
933
  # Backfill runtime CLI modules for existing installs
857
934
  try:
858
- for fname in ("cli.py", "script_registry.py", "skills_runtime.py"):
935
+ for fname in ("cli.py", "script_registry.py", "skills_runtime.py", "cron_recovery.py"):
859
936
  src_file = SRC_DIR / fname
860
937
  dest_file = NEXO_HOME / fname
861
938
  if src_file.is_file() and (not dest_file.exists() or src_file.stat().st_mtime > dest_file.stat().st_mtime):