nexo-brain 7.25.6 → 7.27.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.
Files changed (37) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +5 -1
  3. package/bin/nexo-brain.js +235 -31
  4. package/codex/openai-codex-0.133.0.tgz +0 -0
  5. package/package.json +7 -1
  6. package/src/agent_runner.py +99 -32
  7. package/src/call_model_raw.py +1 -1
  8. package/src/cli.py +117 -4
  9. package/src/client_preferences.py +296 -1
  10. package/src/client_sync.py +343 -6
  11. package/src/db/_schema.py +23 -0
  12. package/src/db/_sessions.py +75 -24
  13. package/src/enforcement_classifier.py +1 -1
  14. package/src/local_context/api.py +58 -45
  15. package/src/model_defaults.json +4 -4
  16. package/src/model_defaults.py +4 -4
  17. package/src/provider_runtime.py +39 -0
  18. package/src/resonance_tiers.json +5 -5
  19. package/src/scripts/deep-sleep/extract.py +2 -0
  20. package/src/scripts/deep-sleep/synthesize.py +1 -0
  21. package/src/scripts/nexo-cron-wrapper.sh +108 -25
  22. package/src/scripts/nexo-morning-agent.py +1 -1
  23. package/src/server.py +3 -1
  24. package/src/tools_automation_sessions.py +2 -1
  25. package/src/tools_sessions.py +13 -8
  26. package/templates/launchagents/README.md +2 -2
  27. package/templates/launchagents/com.nexo.auto-close-sessions.plist +1 -1
  28. package/templates/launchagents/com.nexo.catchup.plist +3 -3
  29. package/templates/launchagents/com.nexo.cognitive-decay.plist +3 -3
  30. package/templates/launchagents/com.nexo.deep-sleep.plist +3 -3
  31. package/templates/launchagents/com.nexo.evolution.plist +3 -3
  32. package/templates/launchagents/com.nexo.followup-hygiene.plist +3 -3
  33. package/templates/launchagents/com.nexo.immune.plist +1 -1
  34. package/templates/launchagents/com.nexo.postmortem.plist +3 -3
  35. package/templates/launchagents/com.nexo.self-audit.plist +3 -3
  36. package/templates/launchagents/com.nexo.synthesis.plist +1 -1
  37. package/templates/launchagents/com.nexo.watchdog.plist +3 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.25.6",
3
+ "version": "7.27.0",
4
4
  "description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
5
5
  "author": {
6
6
  "name": "NEXO Brain",
package/README.md CHANGED
@@ -18,7 +18,11 @@
18
18
 
19
19
  [Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
20
20
 
21
- Version `7.25.6` is the current packaged-runtime line. Patch release over v7.25.5 - existing Local Memory sidecar databases repair legacy root/exclusion columns before source-dependent indexes are created, and core background crons prefer the NEXO-managed Python runtime.
21
+ Version `7.27.0` is the current packaged-runtime line. Minor release over v7.26.0 - Codex-side defaults move to verified `gpt-5.5` resonance tiers, managed config healing follows that model family, and Local Memory file-type actions tolerate transient SQLite locks.
22
+
23
+ Previously in `7.26.0`: minor release over v7.25.6 - provider runtime parity lets Desktop-managed Brain choose Anthropic or OpenAI, keep provider metadata on sessions/automation/crons, and provision the managed OpenAI runtime from bundled Desktop resources.
24
+
25
+ Previously in `7.25.6`: patch release over v7.25.5 - existing Local Memory sidecar databases repair legacy root/exclusion columns before source-dependent indexes are created, and core background crons prefer the NEXO-managed Python runtime.
22
26
 
23
27
  Previously in `7.25.4`: patch release over v7.25.3 - Local Memory starts from safe user-content and email roots, adds configurable included/excluded file types, and cleans legacy whole-disk index state with backup or archive-rebuild safety.
24
28
 
package/bin/nexo-brain.js CHANGED
@@ -18,6 +18,7 @@ const { execSync, spawnSync } = require("child_process");
18
18
  const crypto = require("crypto");
19
19
  const fs = require("fs");
20
20
  const { createRequire } = require("module");
21
+ const os = require("os");
21
22
  const path = require("path");
22
23
  const readline = require("readline");
23
24
  // Force relative launcher helpers to resolve from bin/ even under test harnesses.
@@ -114,8 +115,8 @@ const PUBLIC_CONTRIBUTION_UPSTREAM = "wazionapps/nexo";
114
115
  const MODEL_DEFAULTS_PATH = path.join(__dirname, "..", "src", "model_defaults.json");
115
116
  function _loadModelDefaults() {
116
117
  const fallback = {
117
- claude_code: { model: "claude-opus-4-6[1m]", reasoning_effort: "", display_name: "Opus 4.6 with 1M context" },
118
- codex: { model: "gpt-5.4", reasoning_effort: "xhigh", display_name: "GPT-5.4 with max reasoning" },
118
+ claude_code: { model: "claude-opus-4-7[1m]", reasoning_effort: "max", display_name: "Opus 4.7 with 1M context" },
119
+ codex: { model: "gpt-5.5", reasoning_effort: "xhigh", display_name: "GPT-5.5 with max reasoning" },
119
120
  };
120
121
  try {
121
122
  const raw = JSON.parse(fs.readFileSync(MODEL_DEFAULTS_PATH, "utf8"));
@@ -1672,6 +1673,7 @@ function getDefaultSchedule(timezone) {
1672
1673
  default_terminal_client: "claude_code",
1673
1674
  automation_enabled: true,
1674
1675
  automation_backend: "claude_code",
1676
+ provider_runtime: defaultProviderRuntime("anthropic", "anthropic"),
1675
1677
  // v6.0.0 — model/reasoning_effort have moved to src/resonance_tiers.json
1676
1678
  // keyed by the operator's preferences.default_resonance. The shape
1677
1679
  // below stays so that downstream readers that iterate the profile
@@ -1813,9 +1815,31 @@ function detectInstalledClients() {
1813
1815
  : [];
1814
1816
  const desktopAppPath = desktopApps.find((candidate) => fs.existsSync(candidate)) || "";
1815
1817
  const managedClaudeBin = resolveManagedClaudeBinary();
1818
+ const managedCodexBin = resolveManagedCodexBinary();
1819
+ const desktopManaged = isDesktopManagedInstall();
1820
+ if (desktopManaged) {
1821
+ const managedCodexReady = managedCodexBin && codexVendorPresent(managedClaudePrefix());
1822
+ return {
1823
+ claude_code: {
1824
+ installed: Boolean(managedClaudeBin),
1825
+ path: managedClaudeBin,
1826
+ detectedBy: managedClaudeBin ? "managed_binary" : "missing",
1827
+ },
1828
+ codex: {
1829
+ installed: Boolean(managedCodexReady),
1830
+ path: managedCodexReady ? managedCodexBin : "",
1831
+ detectedBy: managedCodexReady ? "managed_binary" : "missing",
1832
+ },
1833
+ claude_desktop: {
1834
+ installed: Boolean(desktopAppPath || fs.existsSync(desktopConfig)),
1835
+ path: desktopAppPath || desktopConfig,
1836
+ detectedBy: desktopAppPath ? "app" : (fs.existsSync(desktopConfig) ? "config" : "missing"),
1837
+ },
1838
+ };
1839
+ }
1816
1840
  const persistedClaudeBin = readPersistedClaudeCliPath();
1817
1841
  const claudeBin = managedClaudeBin || persistedClaudeBin || run("which claude", { env: buildManagedCliEnv() }) || run("which claude") || "";
1818
- const codexBin = run("which codex") || "";
1842
+ const codexBin = managedCodexBin || run("which codex", { env: buildManagedCliEnv() }) || run("which codex") || "";
1819
1843
  return {
1820
1844
  claude_code: {
1821
1845
  installed: Boolean(claudeBin),
@@ -1905,6 +1929,14 @@ function resolveManagedClaudeBinary() {
1905
1929
  return candidates.find((candidate) => candidate && fs.existsSync(candidate)) || "";
1906
1930
  }
1907
1931
 
1932
+ function resolveManagedCodexBinary() {
1933
+ const prefix = managedClaudePrefix();
1934
+ const candidates = process.platform === "win32"
1935
+ ? [path.join(prefix, "codex.cmd"), path.join(prefix, "bin", "codex.cmd")]
1936
+ : [path.join(prefix, "bin", "codex"), path.join(prefix, "codex")];
1937
+ return candidates.find((candidate) => candidate && fs.existsSync(candidate)) || "";
1938
+ }
1939
+
1908
1940
  function readPersistedClaudeCliPath() {
1909
1941
  const candidates = [
1910
1942
  path.join(NEXO_HOME, "config", "claude-cli-path"),
@@ -2000,6 +2032,60 @@ function defaultClientRuntimeProfiles() {
2000
2032
  };
2001
2033
  }
2002
2034
 
2035
+ function defaultProviderRuntime(selectedProvider = "anthropic", automationProvider = selectedProvider) {
2036
+ const automationBackend = automationProvider === "openai" ? "codex" : (automationProvider === "anthropic" ? "claude_code" : "none");
2037
+ return {
2038
+ schema_version: 1,
2039
+ selected_chat_provider: selectedProvider,
2040
+ automation_provider: automationProvider,
2041
+ automation_backend: automationBackend,
2042
+ providers: {
2043
+ anthropic: {
2044
+ client: "claude_code",
2045
+ runtime_account_status: {
2046
+ surface: "desktop_login",
2047
+ status: "unknown",
2048
+ plan: null,
2049
+ last_checked_at: null,
2050
+ detail: null,
2051
+ },
2052
+ install_status: {
2053
+ installed: false,
2054
+ managed: true,
2055
+ binary_path: null,
2056
+ version: null,
2057
+ },
2058
+ },
2059
+ openai: {
2060
+ client: "codex",
2061
+ runtime_account_status: {
2062
+ surface: "desktop_login",
2063
+ status: "unknown",
2064
+ plan: null,
2065
+ last_checked_at: null,
2066
+ detail: null,
2067
+ },
2068
+ install_status: {
2069
+ installed: false,
2070
+ managed: true,
2071
+ binary_path: null,
2072
+ version: null,
2073
+ },
2074
+ },
2075
+ },
2076
+ fallback_policy: {
2077
+ chat: "ask",
2078
+ automation: "fail_closed",
2079
+ },
2080
+ last_provider_change: {
2081
+ changed_at: null,
2082
+ from_provider: null,
2083
+ to_provider: null,
2084
+ source: null,
2085
+ },
2086
+ };
2087
+ }
2088
+
2003
2089
  function runtimeClientLabel(client) {
2004
2090
  if (client === "claude_code") return "Claude Code";
2005
2091
  if (client === "codex") return "Codex";
@@ -2039,6 +2125,7 @@ function defaultClientSetup(detected) {
2039
2125
  default_terminal_client: "claude_code",
2040
2126
  automation_enabled: true,
2041
2127
  automation_backend: "claude_code",
2128
+ provider_runtime: defaultProviderRuntime("anthropic", "anthropic"),
2042
2129
  client_runtime_profiles: defaultClientRuntimeProfiles(),
2043
2130
  client_install_preferences: {
2044
2131
  claude_code: "ask",
@@ -2057,6 +2144,17 @@ function applyClientSetupToSchedule(schedule, setup) {
2057
2144
  schedule.default_terminal_client = setup.default_terminal_client;
2058
2145
  schedule.automation_enabled = Boolean(setup.automation_enabled);
2059
2146
  schedule.automation_backend = schedule.automation_enabled ? setup.automation_backend : "none";
2147
+ const selectedProvider = setup.default_terminal_client === "codex" ? "openai" : "anthropic";
2148
+ const automationProvider = schedule.automation_backend === "codex"
2149
+ ? "openai"
2150
+ : (schedule.automation_backend === "claude_code" ? "anthropic" : "none");
2151
+ schedule.provider_runtime = {
2152
+ ...defaultProviderRuntime(selectedProvider, automationProvider),
2153
+ ...(setup.provider_runtime || {}),
2154
+ selected_chat_provider: selectedProvider,
2155
+ automation_provider: automationProvider,
2156
+ automation_backend: schedule.automation_backend,
2157
+ };
2060
2158
  schedule.client_runtime_profiles = {
2061
2159
  ...defaultClientRuntimeProfiles(),
2062
2160
  ...(setup.client_runtime_profiles || {}),
@@ -2090,6 +2188,9 @@ function installClaudeCodeCli(platform) {
2090
2188
  const npmViaDesktop = desktopNode && bundledNpmCli;
2091
2189
  let installEnv = buildManagedCliEnv();
2092
2190
  if (desktopNode) installEnv = withDesktopNodeShim(installEnv, desktopNode);
2191
+ if (desktopManaged && !npmViaDesktop) {
2192
+ return { installed: false, path: "" };
2193
+ }
2093
2194
 
2094
2195
  // OFFLINE-FIRST v0.32.4: install claude-code wrapper + ALL its native packs
2095
2196
  // from bundled tarballs. Path: resources/brain-bundle/claude-code/*.tgz.
@@ -2186,22 +2287,7 @@ function installClaudeCodeCli(platform) {
2186
2287
  }
2187
2288
  }
2188
2289
 
2189
- if (desktopManaged) {
2190
- spawnSync(
2191
- "npm",
2192
- ["install", "-g", "--prefix", managedPrefix, "@anthropic-ai/claude-code"],
2193
- {
2194
- stdio: "inherit",
2195
- env: installEnv,
2196
- },
2197
- );
2198
- claudeInstalled = detectInstalledClients().claude_code.path || "";
2199
- if (claudeInstalled) {
2200
- persistClaudeCliPath(claudeInstalled);
2201
- return { installed: true, path: claudeInstalled };
2202
- }
2203
- return { installed: false, path: "" };
2204
- }
2290
+ if (desktopManaged) return { installed: false, path: "" };
2205
2291
 
2206
2292
  spawnSync("npx", ["-y", "@anthropic-ai/claude-code", "--version"], {
2207
2293
  stdio: "pipe",
@@ -2221,11 +2307,128 @@ function installClaudeCodeCli(platform) {
2221
2307
  return { installed: Boolean(claudeInstalled), path: claudeInstalled || "" };
2222
2308
  }
2223
2309
 
2310
+ function installBundledCodexVendor(bundleDir, managedPrefix) {
2311
+ const packageRoots = [
2312
+ path.join(managedPrefix, "lib", "node_modules", "@openai", "codex"),
2313
+ path.join(managedPrefix, "node_modules", "@openai", "codex"),
2314
+ ];
2315
+ const packageRoot = packageRoots.find((candidate) => fs.existsSync(candidate)) || packageRoots[0];
2316
+ if (!fs.existsSync(packageRoot)) return false;
2317
+ const allTgz = fs.readdirSync(bundleDir).filter((f) => f.endsWith(".tgz"));
2318
+ const platformSlug = `${process.platform}-${process.arch}`;
2319
+ const nativePacks = allTgz.filter((f) => f.includes(`-${platformSlug}.tgz`) || f.includes(`-${platformSlug}-`));
2320
+ if (!nativePacks.length) return false;
2321
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "nexo-codex-vendor-"));
2322
+ try {
2323
+ for (const pack of nativePacks) {
2324
+ const tgzPath = path.join(bundleDir, pack);
2325
+ const extract = spawnSync("tar", ["-xzf", tgzPath, "-C", tmpRoot], { stdio: "pipe" });
2326
+ if (extract.status !== 0) continue;
2327
+ const vendorRoot = path.join(tmpRoot, "package", "vendor");
2328
+ if (!fs.existsSync(vendorRoot)) continue;
2329
+ fs.mkdirSync(path.join(packageRoot, "vendor"), { recursive: true });
2330
+ for (const entry of fs.readdirSync(vendorRoot)) {
2331
+ fs.cpSync(path.join(vendorRoot, entry), path.join(packageRoot, "vendor", entry), { recursive: true, force: true });
2332
+ }
2333
+ return true;
2334
+ }
2335
+ } finally {
2336
+ try { fs.rmSync(tmpRoot, { recursive: true, force: true }); } catch {}
2337
+ }
2338
+ return false;
2339
+ }
2340
+
2341
+ function codexVendorPresent(managedPrefix) {
2342
+ const packageRoots = [
2343
+ path.join(managedPrefix, "lib", "node_modules", "@openai", "codex"),
2344
+ path.join(managedPrefix, "node_modules", "@openai", "codex"),
2345
+ ];
2346
+ for (const packageRoot of packageRoots) {
2347
+ const vendorRoot = path.join(packageRoot, "vendor");
2348
+ if (!fs.existsSync(vendorRoot)) continue;
2349
+ try {
2350
+ const stack = [vendorRoot];
2351
+ while (stack.length) {
2352
+ const current = stack.pop();
2353
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
2354
+ const target = path.join(current, entry.name);
2355
+ if (entry.isDirectory()) {
2356
+ stack.push(target);
2357
+ } else if (entry.isFile() && path.basename(path.dirname(target)) === "bin" && entry.name.startsWith("codex")) {
2358
+ return true;
2359
+ }
2360
+ }
2361
+ }
2362
+ } catch {}
2363
+ }
2364
+ return false;
2365
+ }
2366
+
2224
2367
  function installCodexCli() {
2225
- const before = run("which codex");
2226
- if (before) return { installed: true, path: before };
2227
- spawnSync("npm", ["install", "-g", "@openai/codex"], { stdio: "inherit" });
2228
- const codexInstalled = run("which codex") || "";
2368
+ const desktopNode = String(process.env.NEXO_DESKTOP_NODE || "").trim();
2369
+ const bundledNpmCli = String(process.env.NEXO_DESKTOP_NPM_CLI || "").trim();
2370
+ const managedPrefix = managedClaudePrefix();
2371
+ const desktopManaged = isDesktopManagedInstall();
2372
+ let before = detectInstalledClients().codex.path || "";
2373
+ if (before && (!desktopManaged || codexVendorPresent(managedPrefix))) return { installed: true, path: before };
2374
+ if (before && desktopManaged) {
2375
+ log(" Managed Codex wrapper exists, but native vendor is missing; repairing bundled vendor.");
2376
+ }
2377
+ const npmViaDesktop = desktopNode && bundledNpmCli;
2378
+ let installEnv = buildManagedCliEnv();
2379
+ if (desktopNode) installEnv = withDesktopNodeShim(installEnv, desktopNode);
2380
+ if (desktopManaged && !npmViaDesktop) {
2381
+ return { installed: false, path: "" };
2382
+ }
2383
+
2384
+ const bundledCodexDir = path.join(__dirname, "..", "codex");
2385
+ if (fs.existsSync(bundledCodexDir)) {
2386
+ const allTgz = fs.readdirSync(bundledCodexDir).filter((f) => f.endsWith(".tgz")).sort();
2387
+ const wrapper = allTgz.find((f) => /^openai-codex-\d+\.\d+\.\d+\.tgz$/.test(f));
2388
+ if (wrapper) {
2389
+ const tgzPath = path.join(bundledCodexDir, wrapper);
2390
+ log(" Installing Codex from bundled tarball (offline wrapper + native vendor)...");
2391
+ spawnSync(
2392
+ npmViaDesktop ? desktopNode : "npm",
2393
+ [
2394
+ ...(npmViaDesktop ? [bundledNpmCli] : []),
2395
+ "install",
2396
+ "-g",
2397
+ "--prefix",
2398
+ managedPrefix,
2399
+ "--offline",
2400
+ "--no-audit",
2401
+ "--no-fund",
2402
+ tgzPath,
2403
+ ],
2404
+ { stdio: "inherit", env: installEnv },
2405
+ );
2406
+ const bundledVendorInstalled = installBundledCodexVendor(bundledCodexDir, managedPrefix);
2407
+ before = detectInstalledClients().codex.path || "";
2408
+ if (before && bundledVendorInstalled) return { installed: true, path: before };
2409
+ if (before && !bundledVendorInstalled) {
2410
+ log(" Bundled Codex wrapper installed, but native vendor extraction failed; falling back to online install.");
2411
+ }
2412
+ }
2413
+ }
2414
+
2415
+ if (desktopNode && bundledNpmCli) {
2416
+ spawnSync(
2417
+ desktopNode,
2418
+ [bundledNpmCli, "install", "-g", "--prefix", managedPrefix, "@openai/codex"],
2419
+ {
2420
+ stdio: "inherit",
2421
+ env: { ...installEnv, ELECTRON_RUN_AS_NODE: "1" },
2422
+ },
2423
+ );
2424
+ before = detectInstalledClients().codex.path || "";
2425
+ if (before && (!desktopManaged || codexVendorPresent(managedPrefix))) return { installed: true, path: before };
2426
+ }
2427
+
2428
+ if (desktopManaged) return { installed: false, path: "" };
2429
+
2430
+ spawnSync("npm", ["install", "-g", "--prefix", managedPrefix, "@openai/codex"], { stdio: "inherit", env: installEnv });
2431
+ const codexInstalled = detectInstalledClients().codex.path || "";
2229
2432
  return { installed: Boolean(codexInstalled), path: codexInstalled };
2230
2433
  }
2231
2434
 
@@ -2284,19 +2487,19 @@ async function configureClientSetup({ lang, useDefaults, autoInstall, detected }
2284
2487
  const required = requiredCliClients(setup);
2285
2488
  for (const client of required) {
2286
2489
  if (detected[client] && detected[client].installed) continue;
2287
- if (desktopManaged && client === "claude_code") {
2288
- const bundledClaudeDir = path.join(__dirname, "..", "claude-code");
2490
+ if (desktopManaged && (client === "claude_code" || client === "codex")) {
2491
+ const bundledClientDir = path.join(__dirname, "..", client === "claude_code" ? "claude-code" : "codex");
2289
2492
  let hasBundle = false;
2290
2493
  try {
2291
- if (fs.existsSync(bundledClaudeDir)) {
2292
- hasBundle = fs.readdirSync(bundledClaudeDir).some((f) => f.endsWith(".tgz"));
2494
+ if (fs.existsSync(bundledClientDir)) {
2495
+ hasBundle = fs.readdirSync(bundledClientDir).some((f) => f.endsWith(".tgz"));
2293
2496
  }
2294
2497
  } catch (_) {}
2295
2498
  if (!hasBundle) {
2296
- log("Claude Code install deferred to Desktop final sync.");
2499
+ log(`${runtimeClientLabel(client)} install deferred to Desktop final sync.`);
2297
2500
  continue;
2298
2501
  }
2299
- log("Bundled Claude Code tarball detected — installing offline now.");
2502
+ log(`Bundled ${runtimeClientLabel(client)} tarball detected — installing offline now.`);
2300
2503
  }
2301
2504
  let shouldInstall = useDefaults || autoInstall === "auto";
2302
2505
  if (!shouldInstall && process.stdin.isTTY && process.stdout.isTTY) {
@@ -2326,8 +2529,9 @@ async function configureClientSetup({ lang, useDefaults, autoInstall, detected }
2326
2529
  }
2327
2530
 
2328
2531
  if (setup.automation_enabled && setup.automation_backend !== "none" && !detected[setup.automation_backend]?.installed) {
2329
- if (desktopManaged && setup.automation_backend === "claude_code") {
2330
- log("Claude Code will be provisioned by Desktop after the core runtime is ready.");
2532
+ if (desktopManaged && (setup.automation_backend === "claude_code" || setup.automation_backend === "codex")) {
2533
+ const label = setup.automation_backend === "claude_code" ? "Claude Code" : "Codex";
2534
+ log(`${label} will be provisioned by Desktop after the core runtime is ready.`);
2331
2535
  return { setup, detected };
2332
2536
  }
2333
2537
  const label = setup.automation_backend === "claude_code" ? "Claude Code" : "Codex";
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.25.6",
3
+ "version": "7.27.0",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
6
6
  "homepage": "https://nexo-brain.com",
@@ -65,6 +65,11 @@
65
65
  "name": "@anthropic-ai/claude-code",
66
66
  "type": "npm-global",
67
67
  "optional": false
68
+ },
69
+ {
70
+ "name": "@openai/codex",
71
+ "type": "npm-global",
72
+ "optional": true
68
73
  }
69
74
  ],
70
75
  "engines": {
@@ -87,6 +92,7 @@
87
92
  "!templates/**/__pycache__",
88
93
  "!templates/**/*.pyc",
89
94
  "!templates/**/*.pyo",
95
+ "codex/openai-codex-0.133.0.tgz",
90
96
  ".claude-plugin/",
91
97
  ".mcp.json",
92
98
  "hooks/hooks.json",