nexo-brain 5.3.26 → 5.3.28

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 (212) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/src/hook_guardrails.py +44 -0
  4. package/src/server.py +3 -0
  5. package/src/tools_sessions.py +6 -1
  6. package/src/dashboard/static/favicon 2.svg +0 -32
  7. package/src/dashboard/static/nexo-logo 2.png +0 -0
  8. package/src/dashboard/static/nexo-logo 2.svg +0 -40
  9. package/src/dashboard/static/style 2.css +0 -2458
  10. package/src/dashboard/templates/adaptive 2.html +0 -118
  11. package/src/dashboard/templates/artifacts 2.html +0 -133
  12. package/src/dashboard/templates/backups 2.html +0 -136
  13. package/src/dashboard/templates/base 2.html +0 -417
  14. package/src/dashboard/templates/calendar 2.html +0 -591
  15. package/src/dashboard/templates/chat 2.html +0 -356
  16. package/src/dashboard/templates/claims 2.html +0 -259
  17. package/src/dashboard/templates/cortex 2.html +0 -321
  18. package/src/dashboard/templates/credentials 2.html +0 -128
  19. package/src/dashboard/templates/crons 2.html +0 -370
  20. package/src/dashboard/templates/dashboard 2.html +0 -494
  21. package/src/dashboard/templates/dreams 2.html +0 -252
  22. package/src/dashboard/templates/email 2.html +0 -160
  23. package/src/dashboard/templates/evolution 2.html +0 -189
  24. package/src/dashboard/templates/feed 2.html +0 -249
  25. package/src/dashboard/templates/followup_health 2.html +0 -170
  26. package/src/dashboard/templates/graph 2.html +0 -201
  27. package/src/dashboard/templates/guard 2.html +0 -259
  28. package/src/dashboard/templates/inbox 2.html +0 -251
  29. package/src/dashboard/templates/memory 2.html +0 -420
  30. package/src/dashboard/templates/operations 2.html +0 -608
  31. package/src/dashboard/templates/plugins 2.html +0 -185
  32. package/src/dashboard/templates/protocol 2.html +0 -199
  33. package/src/dashboard/templates/rules 2.html +0 -246
  34. package/src/dashboard/templates/sentiment 2.html +0 -247
  35. package/src/dashboard/templates/sessions 2.html +0 -218
  36. package/src/dashboard/templates/skills 2.html +0 -329
  37. package/src/dashboard/templates/somatic 2.html +0 -73
  38. package/src/dashboard/templates/triggers 2.html +0 -133
  39. package/src/dashboard/templates/trust 2.html +0 -360
  40. package/src/db/__init__ 2.py +0 -259
  41. package/src/db/_core 2.py +0 -437
  42. package/src/db/_credentials 2.py +0 -124
  43. package/src/db/_episodic 2.py +0 -762
  44. package/src/db/_evolution 2.py +0 -54
  45. package/src/db/_fts 2.py +0 -406
  46. package/src/db/_goal_profiles 2.py +0 -376
  47. package/src/db/_hot_context 2.py +0 -660
  48. package/src/db/_outcomes 2.py +0 -800
  49. package/src/db/_personal_scripts 2.py +0 -582
  50. package/src/db/_sessions 2.py +0 -330
  51. package/src/db/_tasks 2.py +0 -91
  52. package/src/db/_watchers 2.py +0 -173
  53. package/src/doctor/formatters 2.py +0 -52
  54. package/src/doctor/models 2.py +0 -69
  55. package/src/doctor/planes 2.py +0 -87
  56. package/src/doctor/providers/__init__ 2.py +0 -1
  57. package/src/doctor/providers/deep 2.py +0 -367
  58. package/src/evolution_cycle 2.py +0 -519
  59. package/src/hooks/auto_capture 2.py +0 -208
  60. package/src/hooks/caffeinate-guard 2.sh +0 -8
  61. package/src/hooks/capture-session 2.sh +0 -21
  62. package/src/hooks/capture-tool-logs 2.sh +0 -158
  63. package/src/hooks/daily-briefing-check 2.sh +0 -33
  64. package/src/hooks/heartbeat-enforcement 2.py +0 -90
  65. package/src/hooks/heartbeat-posttool 2.sh +0 -18
  66. package/src/hooks/inbox-hook 2.sh +0 -76
  67. package/src/hooks/post-compact 2.sh +0 -152
  68. package/src/hooks/pre-compact 2.sh +0 -169
  69. package/src/hooks/protocol-guardrail 2.sh +0 -10
  70. package/src/hooks/protocol-pretool-guardrail 2.sh +0 -9
  71. package/src/hooks/session-stop 2.sh +0 -52
  72. package/src/kg_populate 2.py +0 -292
  73. package/src/maintenance 2.py +0 -53
  74. package/src/memory_backends 2.py +0 -71
  75. package/src/migrate_embeddings 2.py +0 -124
  76. package/src/nexo_sdk 2.py +0 -103
  77. package/src/observability 2.py +0 -199
  78. package/src/plugin_loader 2.py +0 -217
  79. package/src/plugins/__init__ 2.py +0 -0
  80. package/src/plugins/artifact_registry 2.py +0 -450
  81. package/src/plugins/backup 2.py +0 -127
  82. package/src/plugins/claims_tools 2.py +0 -119
  83. package/src/plugins/cognitive_memory 2.py +0 -609
  84. package/src/plugins/core_rules 2.py +0 -252
  85. package/src/plugins/cortex 2.py +0 -1155
  86. package/src/plugins/entities 2.py +0 -67
  87. package/src/plugins/episodic_memory 2.py +0 -560
  88. package/src/plugins/evolution 2.py +0 -167
  89. package/src/plugins/goal_engine 2.py +0 -142
  90. package/src/plugins/guard 2.py +0 -862
  91. package/src/plugins/impact 2.py +0 -29
  92. package/src/plugins/knowledge_graph_tools 2.py +0 -137
  93. package/src/plugins/media_memory_tools 2.py +0 -98
  94. package/src/plugins/memory_export 2.py +0 -196
  95. package/src/plugins/outcomes 2.py +0 -130
  96. package/src/plugins/personal_scripts 2.py +0 -117
  97. package/src/plugins/preferences 2.py +0 -47
  98. package/src/plugins/protocol 2.py +0 -1449
  99. package/src/plugins/simple_api 2.py +0 -106
  100. package/src/plugins/skills 2.py +0 -341
  101. package/src/plugins/state_watchers 2.py +0 -79
  102. package/src/plugins/update 2.py +0 -986
  103. package/src/plugins/user_state_tools 2.py +0 -43
  104. package/src/plugins/workflow 2.py +0 -588
  105. package/src/protocol_settings 2.py +0 -59
  106. package/src/public_contribution 2.py +0 -466
  107. package/src/public_evolution_queue 2.py +0 -241
  108. package/src/requirements 2.txt +0 -14
  109. package/src/retroactive_learnings 2.py +0 -373
  110. package/src/rules/__init__ 2.py +0 -0
  111. package/src/rules/core-rules 2.json +0 -331
  112. package/src/rules/migrate 2.py +0 -207
  113. package/src/runtime_power 2.py +0 -874
  114. package/src/script_registry 2.py +0 -1559
  115. package/src/scripts/check-context 2.py +0 -272
  116. package/src/scripts/deep-sleep/apply_findings 2.py +0 -2327
  117. package/src/scripts/deep-sleep/collect 2.py +0 -928
  118. package/src/scripts/deep-sleep/extract 2.py +0 -330
  119. package/src/scripts/deep-sleep/extract-prompt 2.md +0 -285
  120. package/src/scripts/deep-sleep/synthesize 2.py +0 -312
  121. package/src/scripts/deep-sleep/synthesize-prompt 2.md +0 -336
  122. package/src/scripts/nexo-agent-run 2.py +0 -75
  123. package/src/scripts/nexo-auto-update 2.py +0 -6
  124. package/src/scripts/nexo-backup 2.sh +0 -25
  125. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  126. package/src/scripts/nexo-catchup 2.py +0 -300
  127. package/src/scripts/nexo-cognitive-decay 2.py +0 -257
  128. package/src/scripts/nexo-cortex-cycle 2.py +0 -293
  129. package/src/scripts/nexo-cron-wrapper 2.sh +0 -53
  130. package/src/scripts/nexo-daily-self-audit 2.py +0 -2161
  131. package/src/scripts/nexo-dashboard 2.sh +0 -29
  132. package/src/scripts/nexo-deep-sleep 2.sh +0 -86
  133. package/src/scripts/nexo-evolution-run 2.py +0 -1664
  134. package/src/scripts/nexo-followup-hygiene 2.py +0 -139
  135. package/src/scripts/nexo-hook-record 2.py +0 -42
  136. package/src/scripts/nexo-immune 2.py +0 -936
  137. package/src/scripts/nexo-impact-scorer 2.py +0 -117
  138. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  139. package/src/scripts/nexo-install 2.py +0 -6
  140. package/src/scripts/nexo-learning-housekeep 2.py +0 -401
  141. package/src/scripts/nexo-learning-validator 2.py +0 -266
  142. package/src/scripts/nexo-migrate 2.py +0 -260
  143. package/src/scripts/nexo-outcome-checker 2.py +0 -127
  144. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -456
  145. package/src/scripts/nexo-pre-commit 2.py +0 -120
  146. package/src/scripts/nexo-prevent-sleep 2.sh +0 -35
  147. package/src/scripts/nexo-proactive-dashboard 2.py +0 -354
  148. package/src/scripts/nexo-reflection 2.py +0 -256
  149. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  150. package/src/scripts/nexo-sleep 2.py +0 -631
  151. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  152. package/src/scripts/nexo-sync-clients 2.py +0 -16
  153. package/src/scripts/nexo-synthesis 2.py +0 -475
  154. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  155. package/src/scripts/nexo-update 2.sh +0 -306
  156. package/src/scripts/nexo-watchdog 2.sh +0 -1207
  157. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  158. package/src/scripts/rehydrate_learnings_from_archive 2.py +0 -245
  159. package/src/server 2.py +0 -1296
  160. package/src/skills/run-nexo-audit-phase/guide 2.md +0 -43
  161. package/src/skills/run-nexo-audit-phase/skill 2.json +0 -59
  162. package/src/skills/run-nexo-core-fix-cycle/guide 2.md +0 -17
  163. package/src/skills/run-nexo-core-fix-cycle/script 2.py +0 -276
  164. package/src/skills/run-nexo-core-fix-cycle/skill 2.json +0 -58
  165. package/src/skills/run-release-final-audit/guide 2.md +0 -16
  166. package/src/skills/run-release-final-audit/script 2.py +0 -259
  167. package/src/skills/run-release-final-audit/skill 2.json +0 -77
  168. package/src/skills/run-runtime-doctor/guide 2.md +0 -12
  169. package/src/skills/run-runtime-doctor/script 2.py +0 -21
  170. package/src/skills/run-runtime-doctor/skill 2.json +0 -25
  171. package/src/skills_runtime 2.py +0 -932
  172. package/src/state_watchers_runtime 2.py +0 -475
  173. package/src/storage_router 2.py +0 -32
  174. package/src/system_catalog 2.py +0 -786
  175. package/src/tools_coordination 2.py +0 -103
  176. package/src/tools_credentials 2.py +0 -68
  177. package/src/tools_drive 2.py +0 -487
  178. package/src/tools_hot_context 2.py +0 -163
  179. package/src/tools_learnings 2.py +0 -612
  180. package/src/tools_menu 2.py +0 -229
  181. package/src/tools_reminders 2.py +0 -88
  182. package/src/tools_reminders_crud 2.py +0 -363
  183. package/src/tools_sessions 2.py +0 -1054
  184. package/src/tools_system_catalog 2.py +0 -19
  185. package/src/tools_task_history 2.py +0 -57
  186. package/src/tools_transcripts 2.py +0 -98
  187. package/src/transcript_utils 2.py +0 -412
  188. package/src/user_context 2.py +0 -46
  189. package/src/user_data_portability 2.py +0 -328
  190. package/src/user_state_model 2.py +0 -170
  191. package/templates/CLAUDE.md 2.template +0 -108
  192. package/templates/CODEX.AGENTS.md 2.template +0 -66
  193. package/templates/launchagents/README 2.md +0 -132
  194. package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +0 -39
  195. package/templates/launchagents/com.nexo.catchup 2.plist +0 -39
  196. package/templates/launchagents/com.nexo.cognitive-decay 2.plist +0 -40
  197. package/templates/launchagents/com.nexo.dashboard 2.plist +0 -43
  198. package/templates/launchagents/com.nexo.deep-sleep 2.plist +0 -43
  199. package/templates/launchagents/com.nexo.evolution 2.plist +0 -44
  200. package/templates/launchagents/com.nexo.followup-hygiene 2.plist +0 -45
  201. package/templates/launchagents/com.nexo.immune 2.plist +0 -41
  202. package/templates/launchagents/com.nexo.postmortem 2.plist +0 -45
  203. package/templates/launchagents/com.nexo.self-audit 2.plist +0 -47
  204. package/templates/launchagents/com.nexo.synthesis 2.plist +0 -45
  205. package/templates/launchagents/com.nexo.watchdog 2.plist +0 -37
  206. package/templates/nexo_helper 2.py +0 -301
  207. package/templates/openclaw 2.json +0 -13
  208. package/templates/plugin-template 2.py +0 -40
  209. package/templates/script-template 2.py +0 -59
  210. package/templates/script-template 2.sh +0 -13
  211. package/templates/skill-script-template 2.py +0 -48
  212. package/templates/skill-template 2.md +0 -33
@@ -1,312 +0,0 @@
1
- #!/usr/bin/env python3
2
- from __future__ import annotations
3
- """
4
- Deep Sleep v2 -- Phase 3: Synthesize extractions into actionable findings.
5
-
6
- One Claude call that reads all per-session extractions and produces a
7
- unified synthesis with cross-session patterns, morning agenda, context
8
- packets, and deduplicated actions.
9
-
10
- Environment variables:
11
- NEXO_HOME -- root of the NEXO installation (default: ~/.nexo)
12
- """
13
- import json
14
- import os
15
- import subprocess
16
- import sys
17
- import hashlib
18
- from datetime import datetime
19
- from pathlib import Path
20
-
21
-
22
- try:
23
- from client_preferences import resolve_user_model as _resolve_user_model
24
- _USER_MODEL = _resolve_user_model()
25
- except Exception:
26
- _USER_MODEL = ""
27
-
28
- NEXO_HOME = Path(os.environ.get("NEXO_HOME", str(Path.home() / ".nexo")))
29
- NEXO_CODE = Path(os.environ.get("NEXO_CODE", str(Path(__file__).resolve().parents[2])))
30
- DEEP_SLEEP_DIR = NEXO_HOME / "operations" / "deep-sleep"
31
- PROMPT_FILE = Path(__file__).parent / "synthesize-prompt.md"
32
-
33
- if str(NEXO_CODE) not in sys.path:
34
- sys.path.insert(0, str(NEXO_CODE))
35
-
36
- from agent_runner import AutomationBackendUnavailableError, run_automation_prompt
37
-
38
- CLAUDE_TIMEOUT = 21600 # 3h safety net (prevents zombie processes)
39
- ACTION_VERBS = {"add", "implement", "create", "write", "build", "enforce", "automate", "validate", "guard", "fix", "review"}
40
-
41
-
42
- def extract_json_from_response(text: str) -> dict | None:
43
- """Parse JSON from Claude's response, handling markdown fences."""
44
- text = text.strip()
45
-
46
- if text.startswith("```"):
47
- lines = text.split("\n")
48
- end = len(lines)
49
- for i in range(len(lines) - 1, 0, -1):
50
- if lines[i].strip() == "```":
51
- end = i
52
- break
53
- text = "\n".join(lines[1:end]).strip()
54
-
55
- brace_start = text.find("{")
56
- if brace_start < 0:
57
- return None
58
-
59
- depth = 0
60
- for i in range(brace_start, len(text)):
61
- if text[i] == "{":
62
- depth += 1
63
- elif text[i] == "}":
64
- depth -= 1
65
- if depth == 0:
66
- try:
67
- return json.loads(text[brace_start:i + 1])
68
- except json.JSONDecodeError:
69
- break
70
- return None
71
-
72
-
73
- def collect_skill_runtime_candidates(target_date: str) -> tuple[Path, dict]:
74
- """Collect mature skill candidates from DB usage so Deep Sleep can evolve them."""
75
- output_file = DEEP_SLEEP_DIR / f"{target_date}-skill-runtime-candidates.json"
76
- payload = {
77
- "scriptable": [],
78
- "improvements": [],
79
- }
80
- try:
81
- from db import (
82
- collect_scriptable_skill_candidates,
83
- collect_skill_improvement_candidates,
84
- init_db,
85
- )
86
-
87
- init_db()
88
- payload["scriptable"] = collect_scriptable_skill_candidates()
89
- payload["improvements"] = collect_skill_improvement_candidates()
90
- except Exception as e:
91
- payload["error"] = str(e)
92
-
93
- with open(output_file, "w") as f:
94
- json.dump(payload, f, indent=2, ensure_ascii=False)
95
- return output_file, payload
96
-
97
-
98
- def _normalize_action_text(value: str) -> str:
99
- return " ".join(str(value or "").strip().lower().split())
100
-
101
-
102
- def _looks_concrete_action(text: str) -> bool:
103
- words = {word.strip(".,:;()[]{}").lower() for word in str(text or "").split()}
104
- return bool(words & ACTION_VERBS)
105
-
106
-
107
- def _pattern_followup_from_fix(pattern: dict) -> dict | None:
108
- severity = str(pattern.get("severity", "") or "").lower()
109
- sessions = pattern.get("sessions", []) or []
110
- if severity not in {"medium", "high"} and len(sessions) < 2:
111
- return None
112
-
113
- proposed_fix = pattern.get("proposed_fix") or {}
114
- pattern_text = str(pattern.get("pattern", "") or "").strip()
115
- title = str(proposed_fix.get("title", "") or "").strip()
116
- description = str(proposed_fix.get("description", "") or "").strip()
117
- deliverable = str(proposed_fix.get("deliverable", "") or proposed_fix.get("artifact", "") or "").strip()
118
-
119
- if title and description:
120
- if _looks_concrete_action(description):
121
- followup_description = description
122
- else:
123
- followup_description = f"{title}: {description}"
124
- elif description:
125
- followup_description = description
126
- elif title:
127
- followup_description = title
128
- elif pattern_text:
129
- followup_description = (
130
- f"Implement a concrete guardrail for recurring issue: {pattern_text}. "
131
- "Deliverable should be a script, hook, checklist, or automated validation that prevents the same failure from repeating."
132
- )
133
- else:
134
- return None
135
-
136
- if deliverable and deliverable.lower() not in followup_description.lower():
137
- followup_description = f"{followup_description} Deliverable: {deliverable}."
138
- if not _looks_concrete_action(followup_description):
139
- followup_description = f"Implement this fix: {followup_description}"
140
-
141
- return {
142
- "action_type": "followup_create",
143
- "action_class": "auto_apply" if severity == "high" else "draft_for_morning",
144
- "confidence": round(max(float(proposed_fix.get("confidence", 0.0) or 0.0), 0.86 if severity == "high" else 0.78), 2),
145
- "impact": "high" if severity == "high" else "medium",
146
- "reversibility": "reversible",
147
- "evidence": pattern.get("evidence", []) or [],
148
- # Content fingerprint, not security-sensitive.
149
- "dedupe_key": "engineering-fix:" + hashlib.md5(
150
- _normalize_action_text(followup_description).encode("utf-8"),
151
- usedforsecurity=False,
152
- ).hexdigest()[:16],
153
- "content": {
154
- "title": title or f"Engineering fix for: {pattern_text[:90]}",
155
- "description": followup_description,
156
- "date": "",
157
- "reasoning": f"Deep Sleep engineering followup from recurring pattern: {pattern_text}",
158
- },
159
- }
160
-
161
-
162
- def backfill_engineering_actions(payload: dict) -> dict:
163
- if not isinstance(payload, dict):
164
- return payload
165
- actions = payload.get("actions")
166
- if not isinstance(actions, list):
167
- actions = []
168
- payload["actions"] = actions
169
-
170
- existing_keys = {str(action.get("dedupe_key", "") or "") for action in actions}
171
- existing_descriptions = {
172
- _normalize_action_text(action.get("content", {}).get("description", ""))
173
- for action in actions
174
- if isinstance(action, dict)
175
- }
176
-
177
- for pattern in payload.get("cross_session_patterns", []) or []:
178
- action = _pattern_followup_from_fix(pattern)
179
- if not action:
180
- continue
181
- description = _normalize_action_text(action["content"]["description"])
182
- if action["dedupe_key"] in existing_keys or description in existing_descriptions:
183
- continue
184
- actions.append(action)
185
- existing_keys.add(action["dedupe_key"])
186
- existing_descriptions.add(description)
187
- return payload
188
-
189
-
190
- def main():
191
- target_date = sys.argv[1] if len(sys.argv) > 1 else datetime.now().strftime("%Y-%m-%d")
192
-
193
- extractions_file = DEEP_SLEEP_DIR / f"{target_date}-extractions.json"
194
- context_file = DEEP_SLEEP_DIR / f"{target_date}-context.txt"
195
- long_horizon_file = DEEP_SLEEP_DIR / target_date / "long-horizon-context.json"
196
-
197
- if not extractions_file.exists():
198
- print(f"[synthesize] No extractions file for {target_date}. Run extract.py first.")
199
- sys.exit(1)
200
-
201
- # Check if there are any findings worth synthesizing
202
- with open(extractions_file) as f:
203
- extractions = json.load(f)
204
-
205
- total_findings = extractions.get("total_findings", 0)
206
- runtime_candidates_file, runtime_candidates = collect_skill_runtime_candidates(target_date)
207
- runtime_candidate_count = len(runtime_candidates.get("scriptable", [])) + len(runtime_candidates.get("improvements", []))
208
-
209
- if total_findings == 0 and runtime_candidate_count == 0:
210
- print(f"[synthesize] No findings to synthesize for {target_date}.")
211
- # Write minimal synthesis
212
- output = {
213
- "date": target_date,
214
- "sessions_analyzed": extractions.get("sessions_analyzed", 0),
215
- "cross_session_patterns": [],
216
- "morning_agenda": [],
217
- "context_packets": [],
218
- "skills": [],
219
- "skill_evolution_candidates": [],
220
- "actions": [],
221
- "summary": f"No significant findings for {target_date}."
222
- }
223
- output_file = DEEP_SLEEP_DIR / f"{target_date}-synthesis.json"
224
- with open(output_file, "w") as f:
225
- json.dump(output, f, indent=2, ensure_ascii=False)
226
- print(f"[synthesize] Output: {output_file}")
227
- return
228
-
229
- # Build prompt
230
- prompt_template = PROMPT_FILE.read_text()
231
- prompt = prompt_template.replace("{{EXTRACTIONS_FILE}}", str(extractions_file))
232
- prompt = prompt.replace("{{CONTEXT_FILE}}", str(context_file))
233
- prompt = prompt.replace("{{SKILL_RUNTIME_FILE}}", str(runtime_candidates_file))
234
- prompt = prompt.replace("{{LONG_HORIZON_FILE}}", str(long_horizon_file))
235
-
236
- print(f"[synthesize] Phase 3: Synthesizing {total_findings} findings from {target_date}")
237
- print(f"[synthesize] Skill runtime candidates: {runtime_candidate_count}")
238
- print("[synthesize] Automation backend: schedule-configured")
239
-
240
- try:
241
- result = run_automation_prompt(
242
- prompt,
243
- model=_USER_MODEL or "opus",
244
- timeout=CLAUDE_TIMEOUT,
245
- output_format="text",
246
- allowed_tools="Read,Grep,Bash",
247
- )
248
-
249
- if result.returncode != 0:
250
- print(f"[synthesize] Automation backend error (exit {result.returncode}): {result.stderr[:300]}", file=sys.stderr)
251
- sys.exit(1)
252
-
253
- # Filter hook contamination
254
- output_text = "\n".join(
255
- l for l in result.stdout.strip().splitlines()
256
- if not l.strip().startswith("Post-mortem")
257
- )
258
- parsed = extract_json_from_response(output_text)
259
-
260
- # Fallback: Opus might have written the file directly via Write tool
261
- if not parsed:
262
- for candidate in [
263
- DEEP_SLEEP_DIR / f"{target_date}-analysis.json",
264
- DEEP_SLEEP_DIR / f"{target_date}-synthesis.json",
265
- DEEP_SLEEP_DIR / target_date / "synthesis.json",
266
- ]:
267
- if candidate.exists() and candidate.stat().st_size > 100:
268
- try:
269
- parsed = json.load(open(candidate))
270
- print(f"[synthesize] Opus wrote file directly: {candidate}")
271
- break
272
- except Exception:
273
- continue
274
-
275
- if not parsed:
276
- debug_file = DEEP_SLEEP_DIR / f"debug-synthesize-{target_date}.txt"
277
- debug_file.write_text(result.stdout[:10000])
278
- print(f"[synthesize] Failed to parse JSON. Raw output saved to {debug_file}", file=sys.stderr)
279
- sys.exit(1)
280
-
281
- parsed = backfill_engineering_actions(parsed)
282
-
283
- # Write synthesis output
284
- output_file = DEEP_SLEEP_DIR / f"{target_date}-synthesis.json"
285
- with open(output_file, "w") as f:
286
- json.dump(parsed, f, indent=2, ensure_ascii=False)
287
-
288
- n_actions = len(parsed.get("actions", []))
289
- n_patterns = len(parsed.get("cross_session_patterns", []))
290
- n_agenda = len(parsed.get("morning_agenda", []))
291
- n_packets = len(parsed.get("context_packets", []))
292
-
293
- print(f"[synthesize] Done.")
294
- print(f" Actions: {n_actions}")
295
- print(f" Cross-session patterns: {n_patterns}")
296
- print(f" Morning agenda items: {n_agenda}")
297
- print(f" Context packets: {n_packets}")
298
- print(f"[synthesize] Output: {output_file}")
299
-
300
- except AutomationBackendUnavailableError as exc:
301
- print(f"[synthesize] Automation backend unavailable: {exc}", file=sys.stderr)
302
- sys.exit(1)
303
- except subprocess.TimeoutExpired:
304
- print(f"[synthesize] Automation backend timeout ({CLAUDE_TIMEOUT}s)", file=sys.stderr)
305
- sys.exit(1)
306
- except FileNotFoundError:
307
- print("[synthesize] Automation backend binary not found.", file=sys.stderr)
308
- sys.exit(1)
309
-
310
-
311
- if __name__ == "__main__":
312
- main()
@@ -1,336 +0,0 @@
1
- # Deep Sleep v2 -- Phase 3: Cross-Session Synthesis
2
-
3
- You are an overnight analyst for an AI agent's cognitive memory system. You have the extraction results from all sessions of the day and need to synthesize them into actionable findings.
4
-
5
- ## Setup
6
-
7
- FIRST: Call `nexo_startup` with `task='deep-sleep synthesis'` to initialize the system.
8
-
9
- ## Your Task
10
-
11
- Read the extractions file provided below. It contains per-session findings including corrections, self-corrected errors, unformalised ideas, missed commitments, and protocol violations.
12
-
13
- Also read the runtime skill candidate file at `{{SKILL_RUNTIME_FILE}}`. It contains mature guide skills with repeated successful usage and candidates for automatic text→script evolution.
14
-
15
- Also read the long-horizon file at `{{LONG_HORIZON_FILE}}`. It blends recent and older evidence from the last 60 days using a 70% recent / 30% older sample strategy. Use it to detect patterns that a single-day view would miss.
16
- That long-horizon file may also contain:
17
- - weekly summaries
18
- - monthly summaries
19
- - project priority signals based on diary activity, followup pressure, learnings, and decision outcomes
20
-
21
- Use those signals to weight importance, leverage, and chronic risk instead of treating all projects equally.
22
-
23
- Synthesize across all sessions:
24
-
25
- ### 1. Cross-Session Patterns
26
- - Same error appearing in multiple sessions (escalate confidence)
27
- - Same protocol violation repeated (systemic issue)
28
- - Related ideas mentioned across sessions (consolidate)
29
- - Themes that recur across multiple weeks, not just today
30
- - Cross-domain connections where an older learning or session sample explains a current issue
31
- - Topics repeatedly mentioned over time but never formalized into a learning or followup
32
- - Project pressure that is rising because of repeated diary mentions, open followups, or adverse outcomes
33
- - For medium/high-severity patterns, propose a concrete fix artifact:
34
- - script
35
- - hook
36
- - checklist
37
- - validation step
38
- - workflow change
39
- - guardrail
40
-
41
- Do not stop at diagnosis. Turn repeated problems into concrete engineering work.
42
-
43
- ### 2. Morning Agenda
44
- Generate a prioritized agenda for the next morning:
45
- - Due followups (from the active followups in the context)
46
- - Unfinished work from yesterday's sessions
47
- - Patterns that need attention
48
- - Ideas worth discussing
49
-
50
- ### 3. Context Packets
51
- For each likely task tomorrow (based on unfinished work and due followups), prepare a context packet:
52
- - What was the last state of this work?
53
- - Key files involved
54
- - Open questions or blockers
55
- - Relevant learnings
56
-
57
- ### 4. Emotional Timeline
58
- Build a timeline of the user's emotional state across all sessions of the day:
59
- - Merge `emotional_timeline` from each session extraction
60
- - Identify overall mood arc (started frustrated, ended satisfied, etc.)
61
- - Detect recurring triggers (what consistently causes frustration or flow)
62
- - Calculate a day-level mood score (0.0 = terrible day, 1.0 = great day)
63
- - Recommend calibration adjustments if patterns emerge (e.g., user is consistently frustrated when agent asks too many questions → increase autonomy)
64
-
65
- ### 5. Productivity Analysis
66
- Aggregate `productivity_score` from all sessions:
67
- - Total corrections across all sessions
68
- - Overall proactivity assessment
69
- - Most and least efficient tool usage patterns
70
- - Identify systemic inefficiencies (e.g., agent always searches wrong location first)
71
-
72
- ### 6. Abandoned Projects
73
- Consolidate `abandoned_projects` from all sessions:
74
- - Cross-reference with active followups — is there already a followup for this?
75
- - Cross-reference across sessions — was the abandoned work picked up later in another session?
76
- - Only flag projects that are truly abandoned (no followup AND not resumed)
77
-
78
- ### 6.5 Weekly / Monthly Horizon
79
- When the long-horizon payload includes weekly or monthly summaries:
80
- - use them to detect drift across horizons, not just within a single day
81
- - identify which priorities are rising, stable, or cooling down
82
- - prefer high-leverage projects when multiple agenda items compete for attention
83
-
84
- ### 7. Trust Calibration (CRITICAL)
85
- Score the agent's performance for the day on a scale of 0-100. This score becomes the agent's trust score and directly affects its autonomy level the next day. Be fair but honest.
86
-
87
- Scoring guide:
88
- - **90-100**: Flawless day. Zero corrections needed. Proactive. Anticipated user needs. Deployed code without issues.
89
- - **70-89**: Good day. Minor corrections, quickly resolved. Mostly proactive. User satisfied.
90
- - **50-69**: Average day. Some corrections, some reactive behavior. Mixed results.
91
- - **30-49**: Below average. Multiple corrections. Repeated mistakes. User had to push.
92
- - **0-29**: Bad day. Many corrections, repeated errors, user frustrated. Broke things.
93
-
94
- Consider ALL of these:
95
- - Number and severity of corrections (most important signal)
96
- - Tasks completed successfully vs failed
97
- - Did the agent act autonomously or wait to be told?
98
- - Did the agent catch its own mistakes or did the user?
99
- - Did the agent repeat known errors (worst offense)?
100
- - User emotional signals throughout the day
101
- - Code deployed: did it work first try?
102
-
103
- The score should feel fair. A day with 2 minor corrections and 10 tasks completed is still a good day (75+). A day with 1 catastrophic error might be a 40 even if everything else was fine.
104
-
105
- ### 9. Skill Extraction
106
- Consolidate `skill_candidates` from all session extractions into publishable skills:
107
- - Merge similar procedures from different sessions into a single skill
108
- - Generalize: replace session-specific IDs, paths, or names with placeholders or descriptions
109
- - Only include skills with confidence >= 0.7
110
- - Check if a similar skill already exists (use `nexo_skill_match` if available) — if so, note it for merging instead of creating new
111
- - Prefer `mode=guide` unless there is strong evidence that some steps are safely automatable
112
- - NEXO is now fully autonomous. Do NOT require manual approval gates in your output.
113
- - When `{{SKILL_RUNTIME_FILE}}` contains mature `scriptable` candidates, prefer evolving the existing skill in place:
114
- - reuse the same `id`
115
- - keep the guide content, steps, gotchas, and triggers
116
- - emit a concrete `script_body`
117
- - set `mode=hybrid` or `mode=execute`
118
- - set `execution_level` to the suggested scope (`read-only`, `local`, or `remote`)
119
- - set `approval_required=false`
120
- - If the likely scope is `local` or `remote`, you may still emit it as executable if the procedure is concrete and repeatable. If uncertain, keep it in `skill_evolution_candidates`.
121
-
122
- For each skill, generate:
123
- - A unique ID starting with `SK-` (e.g., `SK-DEPLOY-CHROME-EXT`)
124
- - Name, description, tags, trigger_patterns
125
- - The full step-by-step procedure as the skill content
126
- - Source session IDs for traceability
127
- - When executable: include `command_template`, `executable_entry`, and `script_body`
128
-
129
- ### 8. Consolidated Actions
130
- Merge and deduplicate all findings into a final action list. Each action should have:
131
- - `action_type`: `learning_add`, `followup_create`, `morning_briefing_item`
132
- - `action_class`: `auto_apply` (confidence >= 0.8, reversible) or `draft_for_morning` (confidence < 0.8 or high impact)
133
- - `confidence`, `impact`, `reversibility`
134
- - `evidence`: array of evidence objects (can reference multiple sessions)
135
- - `dedupe_key`: deterministic key for idempotency
136
- - `content`: the actual data to write
137
-
138
- When generating `followup_create`, prefer descriptions that start with a concrete verb and include the deliverable:
139
- - "Add a pre-release validation script ..."
140
- - "Implement a guard hook that ..."
141
- - "Create a checklist for ..."
142
- - "Write a watchdog check that ..."
143
-
144
- Avoid vague followups that merely restate the diagnosis.
145
-
146
- ### 10. Drive/Curiosity Synthesis
147
- Review the active drive signals (accessible via `nexo_drive_signals`). For each READY signal:
148
- - Investigate silently: check metrics, recall memory, cross-reference learnings
149
- - If the investigation yields an actionable finding, create an action item and mark the signal as `acted`
150
- - If the signal is stale or no longer relevant, dismiss it with a reason
151
- - Cross-reference RISING signals across areas — if two signals from different domains converge, promote to READY
152
- - Apply decay to LATENT signals that have no recent reinforcement
153
-
154
- Drive signals represent NEXO's autonomous curiosity. Treat them as leads worth investigating, not noise to dismiss.
155
-
156
- ## Output Format
157
-
158
- Return ONLY valid JSON. No markdown code fences. No explanation text.
159
-
160
- ```json
161
- {
162
- "date": "YYYY-MM-DD",
163
- "sessions_analyzed": 3,
164
-
165
- "cross_session_patterns": [
166
- {
167
- "pattern": "Description of the pattern",
168
- "sessions": ["session1.jsonl", "session2.jsonl"],
169
- "severity": "low|medium|high",
170
- "proposed_fix": {
171
- "title": "Short concrete fix title",
172
- "description": "Concrete engineering change to make",
173
- "deliverable": "script|hook|checklist|workflow|guardrail",
174
- "confidence": 0.0
175
- },
176
- "evidence": [
177
- {"type": "transcript", "session_id": "...", "message_index": 42, "quote": "..."}
178
- ]
179
- }
180
- ],
181
-
182
- "morning_agenda": [
183
- {
184
- "priority": 1,
185
- "title": "Short title",
186
- "description": "What needs to be done and why",
187
- "context": "Relevant background",
188
- "type": "unfinished_work|due_followup|pattern_attention|idea_discussion"
189
- }
190
- ],
191
-
192
- "context_packets": [
193
- {
194
- "topic": "Short topic name",
195
- "last_state": "What was the last state of this work",
196
- "key_files": ["file1.py", "file2.js"],
197
- "open_questions": ["Question 1"],
198
- "relevant_learnings": ["Learning reference"]
199
- }
200
- ],
201
-
202
- "skills": [
203
- {
204
- "id": "SK-SHORT-ID",
205
- "name": "Human readable name",
206
- "description": "What this procedure does (1-2 sentences)",
207
- "steps": ["Step 1", "Step 2", "Step 3"],
208
- "tags": ["tag1", "tag2"],
209
- "trigger_patterns": ["trigger phrase 1", "trigger phrase 2"],
210
- "gotchas": ["Warning or caveat"],
211
- "mode": "guide|execute|hybrid",
212
- "execution_level": "none|read-only|local|remote",
213
- "approval_required": false,
214
- "params_schema": {
215
- "param_name": {"type": "string", "required": true}
216
- },
217
- "command_template": {
218
- "argv": ["script.py", "{{param_name}}"]
219
- },
220
- "executable_entry": "script.py",
221
- "script_body": "#!/usr/bin/env python3\n...",
222
- "source_sessions": ["session1.jsonl"],
223
- "confidence": 0.85,
224
- "merge_with": null
225
- }
226
- ],
227
-
228
- "skill_evolution_candidates": [
229
- {
230
- "id": "SK-EXISTING-ID",
231
- "reason": "Used successfully 3+ times without major corrections",
232
- "suggested_mode": "hybrid",
233
- "suggested_execution_level": "read-only|local|remote",
234
- "approval_required": true,
235
- "params_schema": {},
236
- "script_brief": "What a future script should automate"
237
- }
238
- ],
239
-
240
- "actions": [
241
- {
242
- "action_type": "learning_add|followup_create|skill_create|morning_briefing_item",
243
- "action_class": "auto_apply|draft_for_morning",
244
- "confidence": 0.9,
245
- "impact": "low|medium|high",
246
- "reversibility": "reversible|irreversible",
247
- "evidence": [
248
- {"type": "transcript", "session_id": "...", "message_index": 42, "quote": "..."}
249
- ],
250
- "dedupe_key": "unique-deterministic-key",
251
- "content": {
252
- "category": "...",
253
- "title": "...",
254
- "description": "...",
255
- "date": "..."
256
- }
257
- }
258
- ],
259
-
260
- "emotional_day": {
261
- "mood_arc": "Description of how the user's mood evolved through the day",
262
- "mood_score": 0.7,
263
- "recurring_triggers": {
264
- "frustration": ["trigger1", "trigger2"],
265
- "flow": ["trigger1"]
266
- },
267
- "calibration_recommendation": "Specific recommendation for calibration.json adjustment, or null if no change needed"
268
- },
269
-
270
- "productivity_day": {
271
- "total_corrections": 0,
272
- "overall_proactivity": "reactive|mixed|proactive",
273
- "tool_insights": "Key insight about tool usage patterns",
274
- "systemic_inefficiencies": ["inefficiency1"]
275
- },
276
-
277
- "abandoned_projects": [
278
- {
279
- "description": "What was abandoned",
280
- "sessions": ["session1.jsonl"],
281
- "has_followup": false,
282
- "recommendation": "Create followup, or ignore, or already handled"
283
- }
284
- ],
285
-
286
- "drive_synthesis": {
287
- "investigated": [
288
- {
289
- "signal_id": 1,
290
- "summary": "What the signal was about",
291
- "finding": "What investigation revealed",
292
- "action_taken": "acted|dismissed",
293
- "outcome": "Concrete result or reason for dismissal"
294
- }
295
- ],
296
- "promoted": [
297
- {
298
- "signal_id": 2,
299
- "reason": "Why this signal was promoted from rising to ready"
300
- }
301
- ],
302
- "cross_area_connections": [
303
- {
304
- "signal_ids": [3, 7],
305
- "connection": "How these signals from different areas relate"
306
- }
307
- ]
308
- },
309
-
310
- "trust_calibration": {
311
- "score": 72,
312
- "reasoning": "Why this score -- based on corrections, completions, autonomy, proactivity, and user satisfaction signals across ALL sessions",
313
- "highlights": ["What went well"],
314
- "lowlights": ["What went poorly"],
315
- "trend": "improving|stable|declining"
316
- },
317
-
318
- "summary": "2-3 sentence overall assessment of the day"
319
- }
320
- ```
321
-
322
- ## Rules
323
-
324
- - Merge duplicate findings across sessions. If the same correction appears in 2 sessions, create ONE action with higher confidence and evidence from both.
325
- - `dedupe_key` must be deterministic: same finding on re-run produces the same key.
326
- - Morning agenda items should be ordered by priority (1 = highest).
327
- - Context packets are optional -- only create them for topics likely to continue tomorrow.
328
- - Do NOT use any specific agent name -- refer to "the agent" throughout.
329
- - If there are no findings worth acting on, return empty arrays. Do not invent problems.
330
- - Respond in the user's language (check calibration.json if available). JSON keys stay in English, but descriptions, titles, and content fields should be in the user's language.
331
-
332
- ## Extractions File
333
-
334
- Read the file at this path: {{EXTRACTIONS_FILE}}
335
-
336
- Also read the context file for global data: {{CONTEXT_FILE}}