nexo-brain 5.3.20 → 5.3.21

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 (210) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/src/auto_update.py +11 -8
  4. package/src/dashboard/static/favicon 2.svg +32 -0
  5. package/src/dashboard/static/nexo-logo 2.png +0 -0
  6. package/src/dashboard/static/nexo-logo 2.svg +40 -0
  7. package/src/dashboard/static/style 2.css +2458 -0
  8. package/src/dashboard/templates/adaptive 2.html +118 -0
  9. package/src/dashboard/templates/artifacts 2.html +133 -0
  10. package/src/dashboard/templates/backups 2.html +136 -0
  11. package/src/dashboard/templates/base 2.html +417 -0
  12. package/src/dashboard/templates/calendar 2.html +591 -0
  13. package/src/dashboard/templates/chat 2.html +356 -0
  14. package/src/dashboard/templates/claims 2.html +259 -0
  15. package/src/dashboard/templates/cortex 2.html +321 -0
  16. package/src/dashboard/templates/credentials 2.html +128 -0
  17. package/src/dashboard/templates/crons 2.html +370 -0
  18. package/src/dashboard/templates/dashboard 2.html +494 -0
  19. package/src/dashboard/templates/dreams 2.html +252 -0
  20. package/src/dashboard/templates/email 2.html +160 -0
  21. package/src/dashboard/templates/evolution 2.html +189 -0
  22. package/src/dashboard/templates/feed 2.html +249 -0
  23. package/src/dashboard/templates/followup_health 2.html +170 -0
  24. package/src/dashboard/templates/graph 2.html +201 -0
  25. package/src/dashboard/templates/guard 2.html +259 -0
  26. package/src/dashboard/templates/inbox 2.html +251 -0
  27. package/src/dashboard/templates/memory 2.html +420 -0
  28. package/src/dashboard/templates/operations 2.html +608 -0
  29. package/src/dashboard/templates/plugins 2.html +185 -0
  30. package/src/dashboard/templates/protocol 2.html +199 -0
  31. package/src/dashboard/templates/rules 2.html +246 -0
  32. package/src/dashboard/templates/sentiment 2.html +247 -0
  33. package/src/dashboard/templates/sessions 2.html +218 -0
  34. package/src/dashboard/templates/skills 2.html +329 -0
  35. package/src/dashboard/templates/somatic 2.html +73 -0
  36. package/src/dashboard/templates/triggers 2.html +133 -0
  37. package/src/dashboard/templates/trust 2.html +360 -0
  38. package/src/db/__init__ 2.py +259 -0
  39. package/src/db/_core 2.py +437 -0
  40. package/src/db/_credentials 2.py +124 -0
  41. package/src/db/_episodic 2.py +762 -0
  42. package/src/db/_evolution 2.py +54 -0
  43. package/src/db/_fts 2.py +406 -0
  44. package/src/db/_goal_profiles 2.py +376 -0
  45. package/src/db/_hot_context 2.py +660 -0
  46. package/src/db/_outcomes 2.py +800 -0
  47. package/src/db/_personal_scripts 2.py +582 -0
  48. package/src/db/_sessions 2.py +330 -0
  49. package/src/db/_tasks 2.py +91 -0
  50. package/src/db/_watchers 2.py +173 -0
  51. package/src/doctor/formatters 2.py +52 -0
  52. package/src/doctor/models 2.py +69 -0
  53. package/src/doctor/planes 2.py +87 -0
  54. package/src/doctor/providers/__init__ 2.py +1 -0
  55. package/src/doctor/providers/deep 2.py +367 -0
  56. package/src/evolution_cycle 2.py +519 -0
  57. package/src/hooks/auto_capture 2.py +208 -0
  58. package/src/hooks/caffeinate-guard 2.sh +8 -0
  59. package/src/hooks/capture-session 2.sh +21 -0
  60. package/src/hooks/capture-tool-logs 2.sh +158 -0
  61. package/src/hooks/daily-briefing-check 2.sh +33 -0
  62. package/src/hooks/heartbeat-enforcement 2.py +90 -0
  63. package/src/hooks/heartbeat-posttool 2.sh +18 -0
  64. package/src/hooks/inbox-hook 2.sh +76 -0
  65. package/src/hooks/post-compact 2.sh +152 -0
  66. package/src/hooks/pre-compact 2.sh +169 -0
  67. package/src/hooks/protocol-guardrail 2.sh +10 -0
  68. package/src/hooks/protocol-pretool-guardrail 2.sh +9 -0
  69. package/src/hooks/session-stop 2.sh +52 -0
  70. package/src/kg_populate 2.py +292 -0
  71. package/src/maintenance 2.py +53 -0
  72. package/src/memory_backends 2.py +71 -0
  73. package/src/migrate_embeddings 2.py +124 -0
  74. package/src/nexo_sdk 2.py +103 -0
  75. package/src/observability 2.py +199 -0
  76. package/src/plugin_loader 2.py +217 -0
  77. package/src/plugins/__init__ 2.py +0 -0
  78. package/src/plugins/artifact_registry 2.py +450 -0
  79. package/src/plugins/backup 2.py +127 -0
  80. package/src/plugins/claims_tools 2.py +119 -0
  81. package/src/plugins/cognitive_memory 2.py +609 -0
  82. package/src/plugins/core_rules 2.py +252 -0
  83. package/src/plugins/cortex 2.py +1155 -0
  84. package/src/plugins/entities 2.py +67 -0
  85. package/src/plugins/episodic_memory 2.py +560 -0
  86. package/src/plugins/evolution 2.py +167 -0
  87. package/src/plugins/goal_engine 2.py +142 -0
  88. package/src/plugins/guard 2.py +862 -0
  89. package/src/plugins/impact 2.py +29 -0
  90. package/src/plugins/knowledge_graph_tools 2.py +137 -0
  91. package/src/plugins/media_memory_tools 2.py +98 -0
  92. package/src/plugins/memory_export 2.py +196 -0
  93. package/src/plugins/outcomes 2.py +130 -0
  94. package/src/plugins/personal_scripts 2.py +117 -0
  95. package/src/plugins/preferences 2.py +47 -0
  96. package/src/plugins/protocol 2.py +1449 -0
  97. package/src/plugins/simple_api 2.py +106 -0
  98. package/src/plugins/skills 2.py +341 -0
  99. package/src/plugins/state_watchers 2.py +79 -0
  100. package/src/plugins/update 2.py +986 -0
  101. package/src/plugins/user_state_tools 2.py +43 -0
  102. package/src/plugins/workflow 2.py +588 -0
  103. package/src/protocol_settings 2.py +59 -0
  104. package/src/public_contribution 2.py +466 -0
  105. package/src/public_evolution_queue 2.py +241 -0
  106. package/src/requirements 2.txt +14 -0
  107. package/src/retroactive_learnings 2.py +373 -0
  108. package/src/rules/__init__ 2.py +0 -0
  109. package/src/rules/core-rules 2.json +331 -0
  110. package/src/rules/migrate 2.py +207 -0
  111. package/src/runtime_power 2.py +874 -0
  112. package/src/script_registry 2.py +1559 -0
  113. package/src/scripts/check-context 2.py +272 -0
  114. package/src/scripts/deep-sleep/apply_findings 2.py +2327 -0
  115. package/src/scripts/deep-sleep/collect 2.py +928 -0
  116. package/src/scripts/deep-sleep/extract 2.py +330 -0
  117. package/src/scripts/deep-sleep/extract-prompt 2.md +285 -0
  118. package/src/scripts/deep-sleep/synthesize 2.py +312 -0
  119. package/src/scripts/deep-sleep/synthesize-prompt 2.md +336 -0
  120. package/src/scripts/nexo-agent-run 2.py +75 -0
  121. package/src/scripts/nexo-auto-update 2.py +6 -0
  122. package/src/scripts/nexo-backup 2.sh +25 -0
  123. package/src/scripts/nexo-brain-activation 2.sh +140 -0
  124. package/src/scripts/nexo-catchup 2.py +300 -0
  125. package/src/scripts/nexo-cognitive-decay 2.py +257 -0
  126. package/src/scripts/nexo-cortex-cycle 2.py +293 -0
  127. package/src/scripts/nexo-cron-wrapper 2.sh +53 -0
  128. package/src/scripts/nexo-daily-self-audit 2.py +2161 -0
  129. package/src/scripts/nexo-dashboard 2.sh +29 -0
  130. package/src/scripts/nexo-deep-sleep 2.sh +86 -0
  131. package/src/scripts/nexo-evolution-run 2.py +1664 -0
  132. package/src/scripts/nexo-followup-hygiene 2.py +139 -0
  133. package/src/scripts/nexo-hook-record 2.py +42 -0
  134. package/src/scripts/nexo-immune 2.py +936 -0
  135. package/src/scripts/nexo-impact-scorer 2.py +117 -0
  136. package/src/scripts/nexo-inbox-hook 2.sh +74 -0
  137. package/src/scripts/nexo-install 2.py +6 -0
  138. package/src/scripts/nexo-learning-housekeep 2.py +401 -0
  139. package/src/scripts/nexo-learning-validator 2.py +266 -0
  140. package/src/scripts/nexo-migrate 2.py +260 -0
  141. package/src/scripts/nexo-outcome-checker 2.py +127 -0
  142. package/src/scripts/nexo-postmortem-consolidator 2.py +456 -0
  143. package/src/scripts/nexo-pre-commit 2.py +120 -0
  144. package/src/scripts/nexo-prevent-sleep 2.sh +35 -0
  145. package/src/scripts/nexo-proactive-dashboard 2.py +354 -0
  146. package/src/scripts/nexo-reflection 2.py +256 -0
  147. package/src/scripts/nexo-runtime-preflight 2.py +274 -0
  148. package/src/scripts/nexo-sleep 2.py +631 -0
  149. package/src/scripts/nexo-snapshot-restore 2.sh +35 -0
  150. package/src/scripts/nexo-sync-clients 2.py +16 -0
  151. package/src/scripts/nexo-synthesis 2.py +475 -0
  152. package/src/scripts/nexo-tcc-approve 2.sh +79 -0
  153. package/src/scripts/nexo-update 2.sh +306 -0
  154. package/src/scripts/nexo-watchdog 2.sh +1207 -0
  155. package/src/scripts/nexo-watchdog-smoke 2.py +119 -0
  156. package/src/scripts/rehydrate_learnings_from_archive 2.py +245 -0
  157. package/src/server 2.py +1296 -0
  158. package/src/skills/run-nexo-audit-phase/guide 2.md +43 -0
  159. package/src/skills/run-nexo-audit-phase/skill 2.json +59 -0
  160. package/src/skills/run-nexo-core-fix-cycle/guide 2.md +17 -0
  161. package/src/skills/run-nexo-core-fix-cycle/script 2.py +276 -0
  162. package/src/skills/run-nexo-core-fix-cycle/skill 2.json +58 -0
  163. package/src/skills/run-release-final-audit/guide 2.md +16 -0
  164. package/src/skills/run-release-final-audit/script 2.py +259 -0
  165. package/src/skills/run-release-final-audit/skill 2.json +77 -0
  166. package/src/skills/run-runtime-doctor/guide 2.md +12 -0
  167. package/src/skills/run-runtime-doctor/script 2.py +21 -0
  168. package/src/skills/run-runtime-doctor/skill 2.json +25 -0
  169. package/src/skills_runtime 2.py +932 -0
  170. package/src/state_watchers_runtime 2.py +475 -0
  171. package/src/storage_router 2.py +32 -0
  172. package/src/system_catalog 2.py +786 -0
  173. package/src/tools_coordination 2.py +103 -0
  174. package/src/tools_credentials 2.py +68 -0
  175. package/src/tools_drive 2.py +487 -0
  176. package/src/tools_hot_context 2.py +163 -0
  177. package/src/tools_learnings 2.py +612 -0
  178. package/src/tools_menu 2.py +229 -0
  179. package/src/tools_reminders 2.py +88 -0
  180. package/src/tools_reminders_crud 2.py +363 -0
  181. package/src/tools_sessions 2.py +1054 -0
  182. package/src/tools_system_catalog 2.py +19 -0
  183. package/src/tools_task_history 2.py +57 -0
  184. package/src/tools_transcripts 2.py +98 -0
  185. package/src/transcript_utils 2.py +412 -0
  186. package/src/user_context 2.py +46 -0
  187. package/src/user_data_portability 2.py +328 -0
  188. package/src/user_state_model 2.py +170 -0
  189. package/templates/CLAUDE.md 2.template +108 -0
  190. package/templates/CODEX.AGENTS.md 2.template +66 -0
  191. package/templates/launchagents/README 2.md +132 -0
  192. package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +39 -0
  193. package/templates/launchagents/com.nexo.catchup 2.plist +39 -0
  194. package/templates/launchagents/com.nexo.cognitive-decay 2.plist +40 -0
  195. package/templates/launchagents/com.nexo.dashboard 2.plist +43 -0
  196. package/templates/launchagents/com.nexo.deep-sleep 2.plist +43 -0
  197. package/templates/launchagents/com.nexo.evolution 2.plist +44 -0
  198. package/templates/launchagents/com.nexo.followup-hygiene 2.plist +45 -0
  199. package/templates/launchagents/com.nexo.immune 2.plist +41 -0
  200. package/templates/launchagents/com.nexo.postmortem 2.plist +45 -0
  201. package/templates/launchagents/com.nexo.self-audit 2.plist +47 -0
  202. package/templates/launchagents/com.nexo.synthesis 2.plist +45 -0
  203. package/templates/launchagents/com.nexo.watchdog 2.plist +37 -0
  204. package/templates/nexo_helper 2.py +301 -0
  205. package/templates/openclaw 2.json +13 -0
  206. package/templates/plugin-template 2.py +40 -0
  207. package/templates/script-template 2.py +59 -0
  208. package/templates/script-template 2.sh +13 -0
  209. package/templates/skill-script-template 2.py +48 -0
  210. package/templates/skill-template 2.md +33 -0
@@ -0,0 +1,127 @@
1
+ """Backup plugin — hourly SQLite backups with 7-day retention."""
2
+ import os
3
+ import shutil
4
+ import time
5
+ import glob
6
+ from db import get_db
7
+
8
+ NEXO_HOME = os.environ.get("NEXO_HOME", os.path.expanduser("~/.nexo"))
9
+ DB_PATH = os.path.join(NEXO_HOME, "data", "nexo.db")
10
+ BACKUP_DIR = os.path.join(NEXO_HOME, "backups")
11
+
12
+ RETENTION_DAYS = 7
13
+
14
+
15
+ def handle_backup_now() -> str:
16
+ """Create an immediate backup of the NEXO database."""
17
+ os.makedirs(BACKUP_DIR, exist_ok=True)
18
+ timestamp = time.strftime("%Y-%m-%d-%H%M")
19
+ dest = os.path.join(BACKUP_DIR, f"nexo-{timestamp}.db")
20
+
21
+ # Use SQLite backup API for consistency
22
+ import sqlite3
23
+ src_conn = sqlite3.connect(DB_PATH)
24
+ try:
25
+ dst_conn = sqlite3.connect(dest)
26
+ try:
27
+ src_conn.backup(dst_conn)
28
+ finally:
29
+ dst_conn.close()
30
+ finally:
31
+ src_conn.close()
32
+
33
+ size_kb = os.path.getsize(dest) / 1024
34
+ _cleanup_old()
35
+ return f"Backup created: {os.path.basename(dest)} ({size_kb:.0f} KB)"
36
+
37
+
38
+ def handle_backup_list() -> str:
39
+ """List available backups with dates and sizes."""
40
+ if not os.path.isdir(BACKUP_DIR):
41
+ return "No backups."
42
+ files = sorted(glob.glob(os.path.join(BACKUP_DIR, "nexo-*.db")), reverse=True)
43
+ if not files:
44
+ return "No backups."
45
+ lines = [f"BACKUPS ({len(files)}):"]
46
+ total_size = 0
47
+ for f in files:
48
+ size = os.path.getsize(f) / 1024
49
+ total_size += size
50
+ name = os.path.basename(f)
51
+ lines.append(f" {name} ({size:.0f} KB)")
52
+ lines.append(f"\n Total: {total_size/1024:.1f} MB")
53
+ return "\n".join(lines)
54
+
55
+
56
+ def handle_backup_restore(filename: str) -> str:
57
+ """Restore database from a backup file. DESTRUCTIVE — replaces current DB.
58
+
59
+ Args:
60
+ filename: Backup filename (e.g., 'nexo-2026-03-11-1200.db')
61
+ """
62
+ src = os.path.join(BACKUP_DIR, filename)
63
+ if not os.path.isfile(src):
64
+ return f"Backup not found: {filename}"
65
+
66
+ # Create safety backup first
67
+ safety = os.path.join(BACKUP_DIR, f"nexo-pre-restore-{time.strftime('%Y%m%d%H%M%S')}.db")
68
+ import sqlite3
69
+ src_conn = sqlite3.connect(DB_PATH)
70
+ try:
71
+ dst_conn = sqlite3.connect(safety)
72
+ try:
73
+ src_conn.backup(dst_conn)
74
+ finally:
75
+ dst_conn.close()
76
+ finally:
77
+ src_conn.close()
78
+
79
+ # Restore
80
+ restore_conn = sqlite3.connect(src)
81
+ try:
82
+ target_conn = sqlite3.connect(DB_PATH)
83
+ try:
84
+ restore_conn.backup(target_conn)
85
+ finally:
86
+ target_conn.close()
87
+ finally:
88
+ restore_conn.close()
89
+
90
+ # Invalidate shared connection so db.py reconnects to restored data
91
+ import db
92
+ if db._shared_conn is not None:
93
+ try:
94
+ db._shared_conn.close()
95
+ except Exception:
96
+ pass
97
+ db._shared_conn = None
98
+
99
+ return f"DB restaurada desde {filename}. Safety backup: {os.path.basename(safety)}"
100
+
101
+
102
+ def _cleanup_old():
103
+ """Remove backups older than RETENTION_DAYS.
104
+
105
+ Covers both the hourly `nexo-YYYY-MM-DD-HHMM.db` snapshots and the
106
+ `nexo-pre-restore-*.db` safety snapshots created by handle_backup_restore.
107
+ Failures are swallowed — housekeeping must never interrupt the caller.
108
+ """
109
+ if not os.path.isdir(BACKUP_DIR):
110
+ return
111
+ cutoff = time.time() - (RETENTION_DAYS * 86400)
112
+ # glob `nexo-*.db` matches both the hourly pattern and pre-restore
113
+ # snapshots, so a single loop prunes both with a single pass.
114
+ for f in glob.glob(os.path.join(BACKUP_DIR, "nexo-*.db")):
115
+ try:
116
+ if os.path.getmtime(f) < cutoff:
117
+ os.remove(f)
118
+ except OSError:
119
+ # Permission / concurrent removal — skip silently.
120
+ pass
121
+
122
+
123
+ TOOLS = [
124
+ (handle_backup_now, "nexo_backup_now", "Create an immediate backup of the NEXO database"),
125
+ (handle_backup_list, "nexo_backup_list", "List available backups with dates and sizes"),
126
+ (handle_backup_restore, "nexo_backup_restore", "Restore database from a backup (DESTRUCTIVE)"),
127
+ ]
@@ -0,0 +1,119 @@
1
+ """Claims/wiki plugin — public surface over NEXO claim graph."""
2
+
3
+ import claim_graph
4
+
5
+
6
+ def handle_claim_add(
7
+ text: str,
8
+ domain: str = "",
9
+ evidence: str = "",
10
+ confidence: float = 1.0,
11
+ source_type: str = "",
12
+ source_id: str = "",
13
+ freshness_days: int = 30,
14
+ ) -> str:
15
+ result = claim_graph.add_claim(
16
+ text=text,
17
+ domain=domain,
18
+ evidence=evidence,
19
+ confidence=confidence,
20
+ source_type=source_type,
21
+ source_id=source_id,
22
+ freshness_days=freshness_days,
23
+ )
24
+ if result.get("error"):
25
+ return f"ERROR: {result['error']}"
26
+ return f"Claim #{result['id']} {result['action']} (confidence={result['confidence']})"
27
+
28
+
29
+ def handle_claim_search(query: str = "", domain: str = "", status: str = "", limit: int = 20) -> str:
30
+ items = claim_graph.search_claims(query=query, domain=domain, status=status, limit=limit)
31
+ if not items:
32
+ return "No claims found."
33
+ lines = [f"CLAIMS — {len(items)} result(s):", ""]
34
+ for item in items:
35
+ lines.append(
36
+ f" #{item['id']} [{item.get('verification_status','unverified')}] "
37
+ f"freshness={item.get('freshness_state','?')}({item.get('freshness_score',0)})"
38
+ )
39
+ lines.append(f" {item['text'][:220]}")
40
+ if item.get("evidence"):
41
+ lines.append(f" evidence: {str(item['evidence'])[:180]}")
42
+ if item.get("domain"):
43
+ lines.append(f" domain: {item['domain']}")
44
+ return "\n".join(lines)
45
+
46
+
47
+ def handle_claim_get(claim_id: int) -> str:
48
+ item = claim_graph.get_claim(claim_id)
49
+ if not item:
50
+ return f"Claim #{claim_id} not found."
51
+ lines = [
52
+ f"CLAIM #{item['id']}",
53
+ f" status: {item.get('verification_status', 'unverified')}",
54
+ f" confidence: {item.get('confidence', 0)}",
55
+ f" freshness: {item.get('freshness_state', '?')} ({item.get('freshness_score', 0)})",
56
+ f" age_days: {item.get('age_days', 0)}",
57
+ f" domain: {item.get('domain', '') or 'n/a'}",
58
+ f" source: {item.get('source_type', '')}:{item.get('source_id', '')}",
59
+ f" text: {item.get('text', '')}",
60
+ ]
61
+ if item.get("evidence"):
62
+ lines.append(f" evidence: {item['evidence']}")
63
+ if item.get("links_out"):
64
+ lines.append(f" links_out: {len(item['links_out'])}")
65
+ if item.get("links_in"):
66
+ lines.append(f" links_in: {len(item['links_in'])}")
67
+ return "\n".join(lines)
68
+
69
+
70
+ def handle_claim_link(source_claim_id: int, target_claim_id: int, relation: str, confidence: float = 1.0) -> str:
71
+ result = claim_graph.link_claims(source_claim_id, target_claim_id, relation, confidence=confidence)
72
+ if result.get("error"):
73
+ return f"ERROR: {result['error']}"
74
+ return f"Linked claim #{source_claim_id} -> #{target_claim_id} [{relation}]"
75
+
76
+
77
+ def handle_claim_verify(claim_id: int, status: str = "confirmed") -> str:
78
+ result = claim_graph.verify_claim(claim_id, status=status)
79
+ if result.get("error"):
80
+ return f"ERROR: {result['error']}"
81
+ return (
82
+ f"Claim #{result['id']} now {result['verification_status']} "
83
+ f"(freshness={result.get('freshness_state', '?')} {result.get('freshness_score', 0)})"
84
+ )
85
+
86
+
87
+ def handle_claim_lint(max_age_days: int = 30, limit: int = 20) -> str:
88
+ items = claim_graph.lint_claims(max_age_days=max_age_days, limit=limit)
89
+ if not items:
90
+ return "Claim lint: no attention items."
91
+ lines = [f"CLAIM LINT — {len(items)} attention item(s):", ""]
92
+ for item in items:
93
+ lines.append(f" #{item['id']} [{', '.join(item.get('lint_reasons', []))}]")
94
+ lines.append(f" {item['text'][:220]}")
95
+ return "\n".join(lines)
96
+
97
+
98
+ def handle_claim_stats() -> str:
99
+ stats = claim_graph.stats()
100
+ return (
101
+ "CLAIM GRAPH STATS\n"
102
+ f" total: {stats['total_claims']}\n"
103
+ f" links: {stats['total_links']}\n"
104
+ f" contradictions: {stats['contradictions']}\n"
105
+ f" lint_attention: {stats['lint_attention']}\n"
106
+ f" by_status: {stats['by_status']}\n"
107
+ f" by_domain: {stats['by_domain']}"
108
+ )
109
+
110
+
111
+ TOOLS = [
112
+ (handle_claim_add, "nexo_claim_add", "Add a structured claim with provenance, evidence, and freshness."),
113
+ (handle_claim_search, "nexo_claim_search", "Search claims by meaning or filters."),
114
+ (handle_claim_get, "nexo_claim_get", "Get a single claim with its links and freshness metadata."),
115
+ (handle_claim_link, "nexo_claim_link", "Link two claims with supports/contradicts/refines/supersedes."),
116
+ (handle_claim_verify, "nexo_claim_verify", "Verify or reclassify a claim state."),
117
+ (handle_claim_lint, "nexo_claim_lint", "Audit stale, weak, contradictory, or evidence-poor claims."),
118
+ (handle_claim_stats, "nexo_claim_stats", "Claim graph statistics and attention counts."),
119
+ ]