nexo-brain 2.1.0 → 2.3.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 (297) hide show
  1. package/README.md +7 -7
  2. package/bin/nexo-brain.js +53 -26
  3. package/package.json +1 -1
  4. package/scripts/migrate-to-unified 2.sh +813 -0
  5. package/scripts/migrate-v1.5-to-v1.6 2.py +778 -0
  6. package/scripts/migrate-v1.7-to-v1.8 2.py +214 -0
  7. package/scripts/migrate-v1.7-to-v1.8.py +2 -2
  8. package/scripts/nexo-preflight.sh +236 -0
  9. package/scripts/pre-commit-check 2.sh +55 -0
  10. package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
  11. package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
  12. package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
  13. package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
  14. package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
  15. package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
  16. package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
  17. package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
  18. package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
  19. package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
  20. package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
  21. package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
  22. package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
  23. package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
  24. package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
  25. package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
  26. package/src/auto_close_sessions 2.py +159 -0
  27. package/src/auto_update 2.py +634 -0
  28. package/src/auto_update.py +25 -0
  29. package/src/claim_graph 2.py +323 -0
  30. package/src/cognitive/__init__ 2.py +62 -0
  31. package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
  32. package/src/cognitive/__pycache__/__init__.cpython-312.pyc +0 -0
  33. package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
  34. package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
  35. package/src/cognitive/__pycache__/_core.cpython-312.pyc +0 -0
  36. package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
  37. package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
  38. package/src/cognitive/__pycache__/_decay.cpython-312.pyc +0 -0
  39. package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
  40. package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
  41. package/src/cognitive/__pycache__/_ingest.cpython-312.pyc +0 -0
  42. package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
  43. package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
  44. package/src/cognitive/__pycache__/_memory.cpython-312.pyc +0 -0
  45. package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
  46. package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
  47. package/src/cognitive/__pycache__/_search.cpython-312.pyc +0 -0
  48. package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
  49. package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
  50. package/src/cognitive/__pycache__/_trust.cpython-312.pyc +0 -0
  51. package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
  52. package/src/cognitive/_core 2.py +567 -0
  53. package/src/cognitive/_decay 2.py +382 -0
  54. package/src/cognitive/_ingest 2.py +892 -0
  55. package/src/cognitive/_memory 2.py +912 -0
  56. package/src/cognitive/_search 2.py +949 -0
  57. package/src/cognitive/_trust 2.py +464 -0
  58. package/src/cognitive/_trust.py +10 -36
  59. package/src/crons/__pycache__/sync.cpython-314.pyc +0 -0
  60. package/src/crons/manifest 2.json +106 -0
  61. package/src/crons/manifest.json +6 -13
  62. package/src/crons/sync 2.py +217 -0
  63. package/src/crons/sync.py +151 -6
  64. package/src/dashboard/__init__ 2.py +0 -0
  65. package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
  66. package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
  67. package/src/dashboard/app 2.py +789 -0
  68. package/src/db/__init__ 2.py +89 -0
  69. package/src/db/__init__.py +13 -0
  70. package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
  71. package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
  72. package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
  73. package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
  74. package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
  75. package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
  76. package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
  77. package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
  78. package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
  79. package/src/db/__pycache__/_cron_runs.cpython-310.pyc +0 -0
  80. package/src/db/__pycache__/_cron_runs.cpython-314.pyc +0 -0
  81. package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
  82. package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
  83. package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
  84. package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
  85. package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
  86. package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
  87. package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
  88. package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
  89. package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
  90. package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
  91. package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
  92. package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
  93. package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
  94. package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
  95. package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
  96. package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
  97. package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
  98. package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
  99. package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
  100. package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
  101. package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
  102. package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
  103. package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
  104. package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
  105. package/src/db/__pycache__/_skills.cpython-310.pyc +0 -0
  106. package/src/db/__pycache__/_skills.cpython-312.pyc +0 -0
  107. package/src/db/__pycache__/_skills.cpython-314.pyc +0 -0
  108. package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
  109. package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
  110. package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
  111. package/src/db/_core 2.py +417 -0
  112. package/src/db/_credentials 2.py +124 -0
  113. package/src/db/_cron_runs.py +74 -0
  114. package/src/db/_entities 2.py +178 -0
  115. package/src/db/_episodic 2.py +738 -0
  116. package/src/db/_episodic.py +40 -6
  117. package/src/db/_evolution 2.py +54 -0
  118. package/src/db/_fts 2.py +406 -0
  119. package/src/db/_learnings 2.py +168 -0
  120. package/src/db/_reminders 2.py +338 -0
  121. package/src/db/_schema 2.py +364 -0
  122. package/src/db/_schema.py +64 -0
  123. package/src/db/_sessions 2.py +300 -0
  124. package/src/db/_skills.py +514 -0
  125. package/src/db/_tasks 2.py +91 -0
  126. package/src/evolution_cycle 2.py +266 -0
  127. package/src/hnsw_index 2.py +254 -0
  128. package/src/hooks/auto_capture 2.py +208 -0
  129. package/src/hooks/caffeinate-guard 2.sh +8 -0
  130. package/src/hooks/capture-session 2.sh +21 -0
  131. package/src/hooks/capture-session.sh +2 -0
  132. package/src/hooks/capture-tool-logs 2.sh +127 -0
  133. package/src/hooks/capture-tool-logs.sh +3 -2
  134. package/src/hooks/daily-briefing-check 2.sh +33 -0
  135. package/src/hooks/inbox-hook 2.sh +76 -0
  136. package/src/hooks/inbox-hook.sh +3 -2
  137. package/src/hooks/post-compact 2.sh +148 -0
  138. package/src/hooks/post-compact.sh +1 -1
  139. package/src/hooks/pre-compact 2.sh +151 -0
  140. package/src/hooks/pre-compact.sh +1 -1
  141. package/src/hooks/session-start 2.sh +268 -0
  142. package/src/hooks/session-start.sh +6 -3
  143. package/src/hooks/session-stop 2.sh +140 -0
  144. package/src/hooks/session-stop.sh +14 -102
  145. package/src/kg_populate 2.py +290 -0
  146. package/src/knowledge_graph 2.py +257 -0
  147. package/src/maintenance 2.py +59 -0
  148. package/src/migrate_embeddings 2.py +122 -0
  149. package/src/plugin_loader 2.py +202 -0
  150. package/src/plugins/__init__ 2.py +0 -0
  151. package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
  152. package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
  153. package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
  154. package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
  155. package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
  156. package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
  157. package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
  158. package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
  159. package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
  160. package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
  161. package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
  162. package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
  163. package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
  164. package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
  165. package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
  166. package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
  167. package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
  168. package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
  169. package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
  170. package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
  171. package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
  172. package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
  173. package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
  174. package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
  175. package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
  176. package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
  177. package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
  178. package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
  179. package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
  180. package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
  181. package/src/plugins/__pycache__/schedule.cpython-310.pyc +0 -0
  182. package/src/plugins/__pycache__/schedule.cpython-314.pyc +0 -0
  183. package/src/plugins/__pycache__/skills.cpython-310.pyc +0 -0
  184. package/src/plugins/__pycache__/skills.cpython-314.pyc +0 -0
  185. package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
  186. package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
  187. package/src/plugins/adaptive_mode 2.py +805 -0
  188. package/src/plugins/agents 2.py +52 -0
  189. package/src/plugins/artifact_registry 2.py +450 -0
  190. package/src/plugins/backup 2.py +104 -0
  191. package/src/plugins/cognitive_memory 2.py +564 -0
  192. package/src/plugins/core_rules 2.py +252 -0
  193. package/src/plugins/cortex 2.py +299 -0
  194. package/src/plugins/entities 2.py +67 -0
  195. package/src/plugins/episodic_memory 2.py +533 -0
  196. package/src/plugins/episodic_memory.py +5 -3
  197. package/src/plugins/evolution 2.py +115 -0
  198. package/src/plugins/guard 2.py +746 -0
  199. package/src/plugins/knowledge_graph_tools 2.py +105 -0
  200. package/src/plugins/preferences 2.py +47 -0
  201. package/src/plugins/schedule.py +212 -0
  202. package/src/plugins/skills.py +264 -0
  203. package/src/plugins/update 2.py +256 -0
  204. package/src/requirements 2.txt +12 -0
  205. package/src/rules/__init__ 2.py +0 -0
  206. package/src/rules/core-rules 2.json +331 -0
  207. package/src/rules/migrate 2.py +207 -0
  208. package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
  209. package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
  210. package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
  211. package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
  212. package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
  213. package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
  214. package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
  215. package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
  216. package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
  217. package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
  218. package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
  219. package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
  220. package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
  221. package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
  222. package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
  223. package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
  224. package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
  225. package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
  226. package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
  227. package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
  228. package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
  229. package/src/scripts/check-context 2.py +264 -0
  230. package/src/scripts/deep-sleep/apply_findings.py +168 -8
  231. package/src/scripts/deep-sleep/collect.py +33 -11
  232. package/src/scripts/deep-sleep/extract-prompt.md +38 -0
  233. package/src/scripts/deep-sleep/extract.py +80 -8
  234. package/src/scripts/deep-sleep/synthesize-prompt.md +59 -2
  235. package/src/scripts/deep-sleep/synthesize.py +3 -1
  236. package/src/scripts/nexo-auto-update 2.py +6 -0
  237. package/src/scripts/nexo-backup 2.sh +25 -0
  238. package/src/scripts/nexo-brain-activation 2.sh +140 -0
  239. package/src/scripts/nexo-catchup 2.py +242 -0
  240. package/src/scripts/nexo-catchup.py +65 -29
  241. package/src/scripts/nexo-cognitive-decay 2.py +182 -0
  242. package/src/scripts/nexo-cron-wrapper.sh +53 -0
  243. package/src/scripts/nexo-daily-self-audit 2.py +552 -0
  244. package/src/scripts/nexo-daily-self-audit.py +4 -2
  245. package/src/scripts/nexo-deep-sleep 2.sh +97 -0
  246. package/src/scripts/nexo-deep-sleep.sh +66 -77
  247. package/src/scripts/nexo-evolution-run 2.py +597 -0
  248. package/src/scripts/nexo-evolution-run.py +13 -0
  249. package/src/scripts/nexo-followup-hygiene 2.py +112 -0
  250. package/src/scripts/nexo-immune 2.py +927 -0
  251. package/src/scripts/nexo-inbox-hook 2.sh +74 -0
  252. package/src/scripts/nexo-install 2.py +6 -0
  253. package/src/scripts/nexo-learning-housekeep 2.py +245 -0
  254. package/src/scripts/nexo-learning-housekeep.py +156 -1
  255. package/src/scripts/nexo-learning-validator 2.py +207 -0
  256. package/src/scripts/nexo-learning-validator.py +19 -0
  257. package/src/scripts/nexo-migrate 2.py +232 -0
  258. package/src/scripts/nexo-postmortem-consolidator 2.py +421 -0
  259. package/src/scripts/nexo-postmortem-consolidator.py +3 -2
  260. package/src/scripts/nexo-pre-commit 2.py +120 -0
  261. package/src/scripts/nexo-prevent-sleep 2.sh +29 -0
  262. package/src/scripts/nexo-proactive-dashboard 2.py +345 -0
  263. package/src/scripts/nexo-reflection 2.py +253 -0
  264. package/src/scripts/nexo-runtime-preflight 2.py +274 -0
  265. package/src/scripts/nexo-send-email 2.py +25 -0
  266. package/src/scripts/nexo-send-reply 2.py +178 -0
  267. package/src/scripts/nexo-sleep 2.py +592 -0
  268. package/src/scripts/nexo-sleep.py +16 -11
  269. package/src/scripts/nexo-snapshot-restore 2.sh +35 -0
  270. package/src/scripts/nexo-synthesis 2.py +253 -0
  271. package/src/scripts/nexo-synthesis.py +46 -3
  272. package/src/scripts/nexo-tcc-approve 2.sh +79 -0
  273. package/src/scripts/nexo-update 2.sh +161 -0
  274. package/src/scripts/nexo-watchdog 2.sh +878 -0
  275. package/src/scripts/nexo-watchdog-smoke 2.py +119 -0
  276. package/src/scripts/nexo-watchdog.sh +72 -19
  277. package/src/server 2.py +733 -0
  278. package/src/server.py +11 -2
  279. package/src/storage_router 2.py +32 -0
  280. package/src/tools_coordination 2.py +102 -0
  281. package/src/tools_credentials 2.py +68 -0
  282. package/src/tools_learnings 2.py +220 -0
  283. package/src/tools_menu 2.py +227 -0
  284. package/src/tools_reminders 2.py +86 -0
  285. package/src/tools_reminders_crud 2.py +159 -0
  286. package/src/tools_reminders_crud.py +7 -0
  287. package/src/tools_sessions 2.py +476 -0
  288. package/src/tools_task_history 2.py +57 -0
  289. package/templates/CLAUDE.md 2.template +63 -0
  290. package/templates/openclaw 2.json +13 -0
  291. package/tests/__init__ 2.py +0 -0
  292. package/tests/conftest 2.py +71 -0
  293. package/tests/test_cognitive 2.py +205 -0
  294. package/tests/test_knowledge_graph 2.py +140 -0
  295. package/tests/test_migrations 2.py +137 -0
  296. package/src/scripts/deep-sleep/__pycache__/extract.cpython-314.pyc +0 -0
  297. /package/src/scripts/{nexo-github-monitor.py → nexo-github-monitor 2.py} +0 -0
@@ -0,0 +1,364 @@
1
+ """NEXO DB — Schema module."""
2
+ from db._core import get_db
3
+ from db._fts import _migrate_add_column, _migrate_add_index
4
+
5
+ # ── Formal Migration System ─────────────────────────────────────
6
+ #
7
+ # Each migration is (version, name, callable). Migrations run once
8
+ # and are tracked in schema_migrations. The version number MUST be
9
+ # strictly increasing. Add new migrations at the end of the list.
10
+ #
11
+ # For users upgrading via npm/git, init_db() calls run_migrations()
12
+ # automatically — no manual steps needed.
13
+
14
+ def _m1_learnings_columns(conn):
15
+ _migrate_add_column(conn, "learnings", "reasoning", "TEXT")
16
+ _migrate_add_column(conn, "learnings", "prevention", "TEXT DEFAULT ''")
17
+ _migrate_add_column(conn, "learnings", "applies_to", "TEXT DEFAULT ''")
18
+ _migrate_add_column(conn, "learnings", "status", "TEXT DEFAULT 'active'")
19
+ _migrate_add_column(conn, "learnings", "review_due_at", "REAL")
20
+ _migrate_add_column(conn, "learnings", "last_reviewed_at", "REAL")
21
+
22
+ def _m2_followups_reasoning(conn):
23
+ _migrate_add_column(conn, "followups", "reasoning", "TEXT")
24
+ _migrate_add_column(conn, "task_history", "reasoning", "TEXT")
25
+
26
+ def _m3_decisions_review(conn):
27
+ _migrate_add_column(conn, "decisions", "status", "TEXT DEFAULT 'pending_review'")
28
+ _migrate_add_column(conn, "decisions", "review_due_at", "TEXT")
29
+ _migrate_add_column(conn, "decisions", "last_reviewed_at", "TEXT")
30
+ _migrate_add_index(conn, "idx_decisions_domain", "decisions", "domain")
31
+ _migrate_add_index(conn, "idx_decisions_created", "decisions", "created_at")
32
+ _migrate_add_index(conn, "idx_decisions_review_due", "decisions", "review_due_at")
33
+
34
+ def _m4_session_diary_columns(conn):
35
+ _migrate_add_index(conn, "idx_session_diary_sid", "session_diary", "session_id")
36
+ _migrate_add_column(conn, "session_diary", "mental_state", "TEXT")
37
+ _migrate_add_column(conn, "session_diary", "domain", "TEXT")
38
+ _migrate_add_column(conn, "session_diary", "user_signals", "TEXT")
39
+ _migrate_add_column(conn, "session_diary", "self_critique", "TEXT")
40
+
41
+ def _m5_change_log_indexes(conn):
42
+ _migrate_add_index(conn, "idx_change_log_created", "change_log", "created_at")
43
+ _migrate_add_index(conn, "idx_change_log_files", "change_log", "files")
44
+ _migrate_add_index(conn, "idx_learnings_status", "learnings", "status")
45
+ _migrate_add_index(conn, "idx_learnings_review_due", "learnings", "review_due_at")
46
+
47
+ def _m6_error_guard_tables(conn):
48
+ conn.execute("""
49
+ CREATE TABLE IF NOT EXISTS error_repetitions (
50
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
51
+ new_learning_id INTEGER NOT NULL,
52
+ original_learning_id INTEGER NOT NULL,
53
+ similarity REAL NOT NULL,
54
+ area TEXT NOT NULL,
55
+ created_at TEXT DEFAULT (datetime('now'))
56
+ )
57
+ """)
58
+ conn.execute("""
59
+ CREATE TABLE IF NOT EXISTS guard_checks (
60
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
61
+ session_id TEXT,
62
+ files TEXT,
63
+ area TEXT,
64
+ learnings_returned INTEGER DEFAULT 0,
65
+ blocking_rules_returned INTEGER DEFAULT 0,
66
+ created_at TEXT DEFAULT (datetime('now'))
67
+ )
68
+ """)
69
+ _migrate_add_index(conn, "idx_error_repetitions_area", "error_repetitions", "area")
70
+ _migrate_add_index(conn, "idx_guard_checks_session", "guard_checks", "session_id")
71
+
72
+ def _m7_diary_source_and_draft(conn):
73
+ _migrate_add_column(conn, "session_diary", "source", "TEXT DEFAULT 'claude'")
74
+ conn.execute("""
75
+ CREATE TABLE IF NOT EXISTS session_diary_draft (
76
+ sid TEXT PRIMARY KEY,
77
+ summary_draft TEXT DEFAULT '',
78
+ tasks_seen TEXT DEFAULT '[]',
79
+ change_ids TEXT DEFAULT '[]',
80
+ decision_ids TEXT DEFAULT '[]',
81
+ last_context_hint TEXT DEFAULT '',
82
+ heartbeat_count INTEGER DEFAULT 0,
83
+ created_at TEXT DEFAULT (datetime('now')),
84
+ updated_at TEXT DEFAULT (datetime('now'))
85
+ )
86
+ """)
87
+
88
+
89
+ def _m8_adaptive_log_and_somatic(conn):
90
+ conn.execute("""
91
+ CREATE TABLE IF NOT EXISTS adaptive_log (
92
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
93
+ timestamp TEXT DEFAULT (datetime('now')),
94
+ mode TEXT NOT NULL,
95
+ tension_score REAL NOT NULL,
96
+ sig_vibe REAL DEFAULT 0,
97
+ sig_corrections REAL DEFAULT 0,
98
+ sig_brevity REAL DEFAULT 0,
99
+ sig_topic REAL DEFAULT 0,
100
+ sig_tool_errors REAL DEFAULT 0,
101
+ sig_git_diff REAL DEFAULT 0,
102
+ context_hint TEXT DEFAULT '',
103
+ feedback_event TEXT DEFAULT NULL,
104
+ feedback_delta INTEGER DEFAULT NULL,
105
+ feedback_ts TEXT DEFAULT NULL
106
+ )
107
+ """)
108
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_adaptive_log_ts ON adaptive_log(timestamp)")
109
+ conn.execute("""
110
+ CREATE TABLE IF NOT EXISTS somatic_events (
111
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
112
+ timestamp TEXT DEFAULT (datetime('now')),
113
+ target TEXT NOT NULL,
114
+ target_type TEXT NOT NULL,
115
+ event_type TEXT NOT NULL,
116
+ delta REAL NOT NULL,
117
+ source TEXT DEFAULT '',
118
+ projected INTEGER DEFAULT 0
119
+ )
120
+ """)
121
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_somatic_events_target ON somatic_events(target)")
122
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_somatic_events_projected ON somatic_events(projected)")
123
+
124
+
125
+ def _m11_artifact_registry(conn):
126
+ """Artifact Registry — structured index of things NEXO creates/deploys.
127
+
128
+ Solves 'recent work amnesia': services, dashboards, scripts, APIs that
129
+ NEXO builds but can't find hours later because semantic search fails on
130
+ operational vocabulary mismatches (e.g., 'backend' vs 'FastAPI localhost:6174').
131
+
132
+ Design informed by 3-way AI debate (GPT-5.4 + Gemini 3.1 Pro + Claude Opus 4.6).
133
+ Key insight: operational facts need first-class structured storage, not just
134
+ vector embeddings buried in prose diaries.
135
+ """
136
+ conn.execute("""
137
+ CREATE TABLE IF NOT EXISTS artifact_registry (
138
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
139
+ kind TEXT NOT NULL,
140
+ canonical_name TEXT NOT NULL,
141
+ aliases TEXT DEFAULT '[]',
142
+ description TEXT DEFAULT '',
143
+ uri TEXT DEFAULT '',
144
+ ports TEXT DEFAULT '[]',
145
+ paths TEXT DEFAULT '[]',
146
+ run_cmd TEXT DEFAULT '',
147
+ repo TEXT DEFAULT '',
148
+ domain TEXT DEFAULT '',
149
+ state TEXT DEFAULT 'active',
150
+ session_id TEXT DEFAULT '',
151
+ created_at TEXT DEFAULT (datetime('now')),
152
+ last_touched_at TEXT DEFAULT (datetime('now')),
153
+ last_verified_at TEXT DEFAULT NULL,
154
+ metadata TEXT DEFAULT '{}'
155
+ )
156
+ """)
157
+ conn.execute("""
158
+ CREATE TABLE IF NOT EXISTS artifact_aliases (
159
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
160
+ artifact_id INTEGER NOT NULL REFERENCES artifact_registry(id) ON DELETE CASCADE,
161
+ phrase TEXT NOT NULL,
162
+ source TEXT DEFAULT 'manual',
163
+ confidence REAL DEFAULT 1.0,
164
+ created_at TEXT DEFAULT (datetime('now')),
165
+ UNIQUE(artifact_id, phrase)
166
+ )
167
+ """)
168
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_state ON artifact_registry(state)")
169
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_kind ON artifact_registry(kind)")
170
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_domain ON artifact_registry(domain)")
171
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_last_touched ON artifact_registry(last_touched_at)")
172
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_aliases_phrase ON artifact_aliases(phrase)")
173
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_artifact_aliases_aid ON artifact_aliases(artifact_id)")
174
+
175
+
176
+ def _m10_diary_archive(conn):
177
+ """Permanent diary archive — diaries are never truly deleted, just moved here."""
178
+ conn.execute("""
179
+ CREATE TABLE IF NOT EXISTS diary_archive (
180
+ id INTEGER PRIMARY KEY,
181
+ session_id TEXT NOT NULL,
182
+ created_at TEXT NOT NULL,
183
+ decisions TEXT NOT NULL,
184
+ discarded TEXT,
185
+ pending TEXT,
186
+ context_next TEXT,
187
+ summary TEXT NOT NULL,
188
+ mental_state TEXT,
189
+ domain TEXT,
190
+ user_signals TEXT,
191
+ self_critique TEXT DEFAULT '',
192
+ source TEXT DEFAULT 'claude',
193
+ archived_at TEXT DEFAULT (datetime('now'))
194
+ )
195
+ """)
196
+ conn.execute("""
197
+ CREATE INDEX IF NOT EXISTS idx_diary_archive_created
198
+ ON diary_archive (created_at)
199
+ """)
200
+ conn.execute("""
201
+ CREATE INDEX IF NOT EXISTS idx_diary_archive_domain
202
+ ON diary_archive (domain)
203
+ """)
204
+
205
+
206
+ def _m9_maintenance_schedule(conn):
207
+ conn.execute("""
208
+ CREATE TABLE IF NOT EXISTS maintenance_schedule (
209
+ task_name TEXT PRIMARY KEY,
210
+ interval_hours REAL NOT NULL,
211
+ last_run_at TEXT DEFAULT NULL,
212
+ last_duration_ms INTEGER DEFAULT 0,
213
+ run_count INTEGER DEFAULT 0
214
+ )
215
+ """)
216
+ tasks = [
217
+ ('cognitive_decay', 20), ('synthesis', 20), ('self_audit', 144),
218
+ ('weight_learning', 20), ('somatic_projection', 20), ('somatic_decay', 20),
219
+ ('graph_maintenance', 48),
220
+ ]
221
+ for name, hours in tasks:
222
+ conn.execute(
223
+ "INSERT OR IGNORE INTO maintenance_schedule (task_name, interval_hours) VALUES (?, ?)",
224
+ (name, hours)
225
+ )
226
+
227
+
228
+ def _m12_session_checkpoints(conn):
229
+ """Session checkpoints for intelligent auto-compaction.
230
+
231
+ PreCompact saves a checkpoint; PostCompact reads it to re-inject a
232
+ Core Memory Block that preserves continuity after context compression.
233
+ """
234
+ conn.execute("""
235
+ CREATE TABLE IF NOT EXISTS session_checkpoints (
236
+ sid TEXT PRIMARY KEY,
237
+ task TEXT DEFAULT '',
238
+ task_status TEXT DEFAULT 'active',
239
+ active_files TEXT DEFAULT '[]',
240
+ current_goal TEXT DEFAULT '',
241
+ decisions_summary TEXT DEFAULT '',
242
+ errors_found TEXT DEFAULT '',
243
+ reasoning_thread TEXT DEFAULT '',
244
+ next_step TEXT DEFAULT '',
245
+ compaction_count INTEGER DEFAULT 0,
246
+ created_at TEXT DEFAULT (datetime('now')),
247
+ updated_at TEXT DEFAULT (datetime('now'))
248
+ )
249
+ """)
250
+
251
+
252
+ def _m13_claude_session_id(conn):
253
+ """Add claude_session_id to sessions for inter-terminal coordination (D+)."""
254
+ _migrate_add_column(conn, "sessions", "claude_session_id", "TEXT DEFAULT ''")
255
+ _migrate_add_index(conn, "idx_sessions_claude_sid", "sessions", "claude_session_id")
256
+ conn.commit()
257
+
258
+
259
+ def _m14_learnings_priority_weight(conn):
260
+ """Add priority, weight, and guard usage tracking to learnings + followup priority."""
261
+ _migrate_add_column(conn, "learnings", "priority", "TEXT DEFAULT 'medium'")
262
+ _migrate_add_column(conn, "learnings", "weight", "REAL DEFAULT 0.5")
263
+ _migrate_add_column(conn, "learnings", "guard_hits", "INTEGER DEFAULT 0")
264
+ _migrate_add_column(conn, "learnings", "last_guard_hit_at", "REAL")
265
+ _migrate_add_column(conn, "followups", "priority", "TEXT DEFAULT 'medium'")
266
+
267
+
268
+ def _m15_core_rules_tables(conn):
269
+ """Core rules and version tracking tables for the core_rules plugin."""
270
+ conn.execute("""
271
+ CREATE TABLE IF NOT EXISTS core_rules (
272
+ id TEXT PRIMARY KEY,
273
+ category TEXT NOT NULL,
274
+ rule TEXT NOT NULL,
275
+ why TEXT NOT NULL,
276
+ importance INTEGER NOT NULL DEFAULT 3,
277
+ type TEXT NOT NULL DEFAULT 'advisory',
278
+ added_in TEXT DEFAULT '',
279
+ removed_in TEXT DEFAULT NULL,
280
+ is_active INTEGER NOT NULL DEFAULT 1
281
+ )
282
+ """)
283
+ conn.execute("""
284
+ CREATE TABLE IF NOT EXISTS core_rules_version (
285
+ id INTEGER PRIMARY KEY,
286
+ version TEXT NOT NULL DEFAULT '0.0.0',
287
+ updated_at TEXT DEFAULT (datetime('now'))
288
+ )
289
+ """)
290
+ # Seed the version row so UPDATE statements in the plugin always find it
291
+ conn.execute(
292
+ "INSERT OR IGNORE INTO core_rules_version (id, version) VALUES (1, '0.0.0')"
293
+ )
294
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_core_rules_category ON core_rules(category)")
295
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_core_rules_active ON core_rules(is_active)")
296
+
297
+
298
+ # Migration registry — APPEND ONLY, never reorder or delete
299
+ MIGRATIONS = [
300
+ (1, "learnings_columns", _m1_learnings_columns),
301
+ (2, "followups_reasoning", _m2_followups_reasoning),
302
+ (3, "decisions_review", _m3_decisions_review),
303
+ (4, "session_diary_columns", _m4_session_diary_columns),
304
+ (5, "change_log_indexes", _m5_change_log_indexes),
305
+ (6, "error_guard_tables", _m6_error_guard_tables),
306
+ (7, "diary_source_and_draft", _m7_diary_source_and_draft),
307
+ (8, "adaptive_log_and_somatic", _m8_adaptive_log_and_somatic),
308
+ (9, "maintenance_schedule", _m9_maintenance_schedule),
309
+ (10, "diary_archive", _m10_diary_archive),
310
+ (11, "artifact_registry", _m11_artifact_registry),
311
+ (12, "session_checkpoints", _m12_session_checkpoints),
312
+ (13, "claude_session_id", _m13_claude_session_id),
313
+ (14, "learnings_priority_weight", _m14_learnings_priority_weight),
314
+ (15, "core_rules_tables", _m15_core_rules_tables),
315
+ ]
316
+
317
+
318
+ def run_migrations(conn=None):
319
+ """Run pending migrations. Tracks applied versions in schema_migrations.
320
+
321
+ Safe to call multiple times — skips already-applied migrations.
322
+ Called automatically by init_db() on every server start.
323
+ """
324
+ if conn is None:
325
+ conn = get_db()
326
+
327
+ conn.execute("""
328
+ CREATE TABLE IF NOT EXISTS schema_migrations (
329
+ version INTEGER PRIMARY KEY,
330
+ name TEXT NOT NULL,
331
+ applied_at TEXT DEFAULT (datetime('now'))
332
+ )
333
+ """)
334
+ conn.commit()
335
+
336
+ applied = {r[0] for r in conn.execute("SELECT version FROM schema_migrations").fetchall()}
337
+
338
+ for version, name, fn in MIGRATIONS:
339
+ if version not in applied:
340
+ try:
341
+ fn(conn)
342
+ conn.execute(
343
+ "INSERT INTO schema_migrations (version, name) VALUES (?, ?)",
344
+ (version, name)
345
+ )
346
+ conn.commit()
347
+ except Exception as e:
348
+ # Log but don't crash — partial migration is better than no server
349
+ import sys
350
+ print(f"[MIGRATION] v{version} ({name}) failed: {e}", file=sys.stderr)
351
+
352
+ return len(MIGRATIONS) - len(applied)
353
+
354
+
355
+ def get_schema_version() -> int:
356
+ """Return the highest applied migration version, or 0 if none."""
357
+ conn = get_db()
358
+ try:
359
+ row = conn.execute("SELECT MAX(version) FROM schema_migrations").fetchone()
360
+ return row[0] or 0
361
+ except Exception:
362
+ return 0
363
+
364
+
package/src/db/_schema.py CHANGED
@@ -295,7 +295,69 @@ def _m15_core_rules_tables(conn):
295
295
  conn.execute("CREATE INDEX IF NOT EXISTS idx_core_rules_active ON core_rules(is_active)")
296
296
 
297
297
 
298
+ def _m16_skills_tables(conn):
299
+ """Skill Auto-Creation system — reusable procedures extracted from complex tasks.
300
+
301
+ Skills are procedural knowledge (step-by-step how-tos) vs learnings which are
302
+ declarative (don't do X). Pipeline: trace → draft → published, fully autonomous.
303
+ Trust score with decay controls quality without human approval gates.
304
+ """
305
+ conn.execute("""
306
+ CREATE TABLE IF NOT EXISTS skills (
307
+ id TEXT PRIMARY KEY,
308
+ name TEXT NOT NULL,
309
+ description TEXT DEFAULT '',
310
+ level TEXT NOT NULL DEFAULT 'trace',
311
+ trust_score INTEGER NOT NULL DEFAULT 50,
312
+ file_path TEXT DEFAULT '',
313
+ tags TEXT DEFAULT '[]',
314
+ trigger_patterns TEXT DEFAULT '[]',
315
+ source_sessions TEXT DEFAULT '[]',
316
+ linked_learnings TEXT DEFAULT '[]',
317
+ use_count INTEGER DEFAULT 0,
318
+ success_count INTEGER DEFAULT 0,
319
+ fail_count INTEGER DEFAULT 0,
320
+ created_at TEXT DEFAULT (datetime('now')),
321
+ last_used_at TEXT DEFAULT NULL,
322
+ updated_at TEXT DEFAULT (datetime('now'))
323
+ )
324
+ """)
325
+ conn.execute("""
326
+ CREATE TABLE IF NOT EXISTS skill_usage (
327
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
328
+ skill_id TEXT NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
329
+ session_id TEXT DEFAULT '',
330
+ success INTEGER NOT NULL DEFAULT 1,
331
+ context TEXT DEFAULT '',
332
+ notes TEXT DEFAULT '',
333
+ created_at TEXT DEFAULT (datetime('now'))
334
+ )
335
+ """)
336
+ _migrate_add_index(conn, "idx_skills_level", "skills", "level")
337
+ _migrate_add_index(conn, "idx_skills_trust", "skills", "trust_score")
338
+ _migrate_add_index(conn, "idx_skills_last_used", "skills", "last_used_at")
339
+ _migrate_add_index(conn, "idx_skill_usage_skill_id", "skill_usage", "skill_id")
340
+ _migrate_add_index(conn, "idx_skill_usage_created", "skill_usage", "created_at")
341
+
342
+
298
343
  # Migration registry — APPEND ONLY, never reorder or delete
344
+ def _m17_cron_runs(conn):
345
+ conn.execute("""
346
+ CREATE TABLE IF NOT EXISTS cron_runs (
347
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
348
+ cron_id TEXT NOT NULL,
349
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
350
+ ended_at TEXT,
351
+ exit_code INTEGER,
352
+ summary TEXT DEFAULT '',
353
+ error TEXT DEFAULT '',
354
+ duration_secs REAL
355
+ )
356
+ """)
357
+ _migrate_add_index(conn, "idx_cron_runs_cron_id", "cron_runs", "cron_id")
358
+ _migrate_add_index(conn, "idx_cron_runs_started", "cron_runs", "started_at")
359
+
360
+
299
361
  MIGRATIONS = [
300
362
  (1, "learnings_columns", _m1_learnings_columns),
301
363
  (2, "followups_reasoning", _m2_followups_reasoning),
@@ -312,6 +374,8 @@ MIGRATIONS = [
312
374
  (13, "claude_session_id", _m13_claude_session_id),
313
375
  (14, "learnings_priority_weight", _m14_learnings_priority_weight),
314
376
  (15, "core_rules_tables", _m15_core_rules_tables),
377
+ (16, "skills_tables", _m16_skills_tables),
378
+ (17, "cron_runs", _m17_cron_runs),
315
379
  ]
316
380
 
317
381