nexo-brain 1.5.1 → 1.5.3

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.
package/README.md CHANGED
@@ -130,10 +130,22 @@ Like a human brain, NEXO Brain has automated processes that run while you're not
130
130
  |------|---------|---------------|
131
131
  | 03:00 | Decay + memory consolidation + merge duplicates + dreaming | Deep sleep consolidation |
132
132
  | 04:00 | Clean expired data, prune redundant memories | Synaptic pruning |
133
+ | 04:30 | **Deep Sleep** — analyze full session transcripts for uncaptured corrections, protocol violations, missed commitments | REM sleep review |
133
134
  | 07:00 | Self-audit, health checks, metrics | Waking up + orientation |
134
135
  | 23:30 | Process day's events, extract patterns | Pre-sleep reflection |
135
136
  | Boot | Catch-up: run anything missed while computer was off | -- |
136
137
 
138
+ #### Deep Sleep (v1.5.2)
139
+
140
+ Deep Sleep reads your **complete session transcripts** (not just the diary summary) and finds what the agent missed during the day:
141
+
142
+ - **Uncaptured corrections** — user corrections the agent didn't save as learnings
143
+ - **Protocol violations** — guard_check skipped, trust not adjusted, change_log omitted
144
+ - **Missed commitments** — things mentioned but never tracked as followups
145
+ - **Quality issues** — agent declaring "done" when work wasn't complete
146
+
147
+ Uses Claude CLI in `--bare` mode (no hooks, no CLAUDE.md interference). Catch-up system re-runs yesterday if the Mac was off.
148
+
137
149
  If your Mac was asleep during any scheduled process, NEXO Brain catches up in order when it wakes.
138
150
 
139
151
  ## Cognitive Cortex
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO — Cognitive co-operator for Claude Code. Atkinson-Shiffrin memory, semantic RAG, knowledge graph, HNSW vector indexing, trust scoring, and metacognitive error prevention.",
6
6
  "bin": {
@@ -79,6 +79,44 @@ def adjust_trust(points: int, context: str):
79
79
  pass
80
80
 
81
81
 
82
+ def add_learning(category: str, title: str, content: str) -> bool:
83
+ """Add a learning to nexo.db using real schema."""
84
+ if not NEXO_DB.exists():
85
+ return False
86
+ try:
87
+ now = datetime.now().timestamp()
88
+ conn = sqlite3.connect(str(NEXO_DB))
89
+ conn.execute(
90
+ "INSERT INTO learnings (category, title, content, created_at, updated_at, reasoning) VALUES (?, ?, ?, ?, ?, ?)",
91
+ (category, title, content, now, now, "Deep Sleep overnight analysis")
92
+ )
93
+ conn.commit()
94
+ conn.close()
95
+ return True
96
+ except Exception as e:
97
+ print(f" Error adding learning: {e}", file=sys.stderr)
98
+ return False
99
+
100
+
101
+ def add_followup(followup_id: str, description: str, date: str = None) -> bool:
102
+ """Add a followup to nexo.db using real schema."""
103
+ if not NEXO_DB.exists():
104
+ return False
105
+ try:
106
+ now = datetime.now().timestamp()
107
+ conn = sqlite3.connect(str(NEXO_DB))
108
+ conn.execute(
109
+ "INSERT OR IGNORE INTO followups (id, description, date, status, created_at, updated_at, reasoning) VALUES (?, ?, ?, 'PENDIENTE', ?, ?, ?)",
110
+ (followup_id, description, date or "", now, now, "Deep Sleep overnight analysis")
111
+ )
112
+ conn.commit()
113
+ conn.close()
114
+ return True
115
+ except Exception as e:
116
+ print(f" Error adding followup: {e}", file=sys.stderr)
117
+ return False
118
+
119
+
82
120
  def apply(analysis: dict):
83
121
  """Apply all findings from deep sleep analysis."""
84
122
  memory_dir = find_memory_dir()
@@ -88,32 +126,44 @@ def apply(analysis: dict):
88
126
 
89
127
  print(f"\nApplying findings for {date}...")
90
128
 
91
- # 1. Uncaptured corrections → feedback memories (high/critical only)
129
+ # 1. Uncaptured corrections → learnings + feedback memories
92
130
  for i, correction in enumerate(analysis.get("uncaptured_corrections", [])):
93
131
  severity = correction.get("severity", "medium")
94
- if severity not in ("high", "critical"):
95
- continue
96
-
97
132
  category = correction.get("category", "process")
98
133
  content = correction.get("what_nexo_should_have_saved", "")
99
134
  quote = correction.get("quote", "")
100
135
 
101
- safe_name = category.replace(" ", "_").lower()
102
- filename = f"ds_{date}_{safe_name}_{i}.md"
103
- write_feedback_memory(
104
- memory_dir, filename,
105
- name=content[:60],
106
- description=f"Deep sleep detected uncaptured correction ({severity})",
107
- content=f"{content}\n\n**Why:** User said: \"{quote}\"\nContext: {correction.get('context', '')}\n\n**How to apply:** {content}"
108
- )
109
- memory_entries.append({
110
- "title": content[:40],
111
- "filename": filename,
112
- "summary": f"Deep sleep {date}, severity {severity}"
113
- })
114
- actions_taken.append(f"feedback_write: {filename}")
115
-
116
- # 2. Trust adjustments for critical violations
136
+ # All corrections learnings
137
+ learning_title = f"[Deep Sleep] {content[:80]}"
138
+ learning_content = f"User said: \"{quote}\"\nContext: {correction.get('context', '')}\nRepeated: {correction.get('times_repeated', 1)} times"
139
+ if add_learning(category, learning_title, learning_content):
140
+ actions_taken.append(f"learning_add: {learning_title[:50]}")
141
+
142
+ # High/critical also feedback memories
143
+ if severity in ("high", "critical"):
144
+ safe_name = category.replace(" ", "_").lower()
145
+ filename = f"ds_{date}_{safe_name}_{i}.md"
146
+ write_feedback_memory(
147
+ memory_dir, filename,
148
+ name=content[:60],
149
+ description=f"Deep sleep detected uncaptured correction ({severity})",
150
+ content=f"{content}\n\n**Why:** User said: \"{quote}\"\nContext: {correction.get('context', '')}\n\n**How to apply:** {content}"
151
+ )
152
+ memory_entries.append({
153
+ "title": content[:40],
154
+ "filename": filename,
155
+ "summary": f"Deep sleep {date}, severity {severity}"
156
+ })
157
+ actions_taken.append(f"feedback_write: {filename}")
158
+
159
+ # 2. Missed commitments → followups
160
+ for i, commitment in enumerate(analysis.get("missed_commitments", [])):
161
+ fid = f"NF-DS-{date}-{i}"
162
+ desc = f"[Deep Sleep] {commitment.get('commitment', '')[:100]}"
163
+ if add_followup(fid, desc, commitment.get("due_date")):
164
+ actions_taken.append(f"followup: {desc[:50]}")
165
+
166
+ # 3. Trust adjustments for critical violations
117
167
  critical_violations = [v for v in analysis.get("protocol_violations", []) if v.get("severity") == "critical"]
118
168
  if critical_violations:
119
169
  points = -3 * len(critical_violations)
@@ -1,14 +1,13 @@
1
1
  #!/bin/bash
2
- # NEXO Deep Sleep — Complete overnight session transcript analysis
3
- # Reads ALL Claude Code session transcripts from the day, analyzes with
4
- # Claude CLI (bare mode), and applies findings as feedback memories.
2
+ # NEXO Deep Sleep — Complete overnight session analysis
3
+ # Runs at 4:30 AM via LaunchAgent
4
+ # Reads ALL session transcripts from the day, analyzes with Claude CLI,
5
+ # and applies findings (learnings, feedbacks, followups, trust adjustments)
5
6
  #
6
7
  # Features:
7
8
  # - Catch-up: if yesterday was missed (Mac off/asleep), runs it first
8
- # - Uses --bare mode to avoid loading NEXO hooks during analysis
9
- # - Requires ANTHROPIC_API_KEY env var or ~/.claude/anthropic-api-key.txt
10
- #
11
- # Install: Add as LaunchAgent for daily execution (recommended: 4:30 AM)
9
+ # - Logs to ~/claude/logs/deep-sleep.log
10
+ # - Marks completion in .last-run for watchdog monitoring
12
11
 
13
12
  set -euo pipefail
14
13
 
@@ -26,9 +25,11 @@ run_analysis() {
26
25
  local DATE="$1"
27
26
  log "=== Deep Sleep starting for $DATE ==="
28
27
 
28
+ # Step 1: Collect transcripts
29
29
  log "Step 1: Collecting transcripts for $DATE..."
30
30
  python3 "$SCRIPT_DIR/deep-sleep/collect_transcripts.py" "$DATE" 2>&1 | tee -a "$LOG_DIR/deep-sleep.log"
31
31
 
32
+ # Check if transcripts were found
32
33
  if [ ! -f "$DEEP_SLEEP_DIR/$DATE-transcripts.json" ]; then
33
34
  log "No transcripts file generated for $DATE. Skipping."
34
35
  return 0
@@ -40,6 +41,7 @@ run_analysis() {
40
41
  return 0
41
42
  fi
42
43
 
44
+ # Step 2: Analyze with Claude CLI
43
45
  log "Step 2: Analyzing $SESSIONS sessions with Claude CLI..."
44
46
  python3 "$SCRIPT_DIR/deep-sleep/analyze_session.py" "$DATE" 2>&1 | tee -a "$LOG_DIR/deep-sleep.log"
45
47
 
@@ -48,6 +50,7 @@ run_analysis() {
48
50
  return 1
49
51
  fi
50
52
 
53
+ # Step 3: Apply findings
51
54
  log "Step 3: Applying findings for $DATE..."
52
55
  python3 "$SCRIPT_DIR/deep-sleep/apply_findings.py" "$DATE" 2>&1 | tee -a "$LOG_DIR/deep-sleep.log"
53
56
 
@@ -55,22 +58,24 @@ run_analysis() {
55
58
  return 0
56
59
  }
57
60
 
58
- # --- Catch-up: check if yesterday was missed ---
61
+ # --- Catch-up: check if the day before yesterday was missed ---
59
62
  YESTERDAY=$(date -v-1d +%Y-%m-%d 2>/dev/null || date -d "yesterday" +%Y-%m-%d 2>/dev/null)
63
+ DAY_BEFORE=$(date -v-2d +%Y-%m-%d 2>/dev/null || date -d "2 days ago" +%Y-%m-%d 2>/dev/null)
60
64
  LAST_RUN=""
61
65
  if [ -f "$LAST_RUN_FILE" ]; then
62
66
  LAST_RUN=$(cat "$LAST_RUN_FILE")
63
67
  fi
64
68
 
65
- if [ -n "$YESTERDAY" ] && [ "$LAST_RUN" != "$YESTERDAY" ] && [ "$LAST_RUN" != "$TODAY" ]; then
66
- if [ ! -f "$DEEP_SLEEP_DIR/$YESTERDAY-analysis.json" ]; then
67
- log "*** CATCH-UP: $YESTERDAY was missed. Running now. ***"
68
- run_analysis "$YESTERDAY" || log "Catch-up for $YESTERDAY failed."
69
+ if [ -n "$DAY_BEFORE" ] && [ "$LAST_RUN" != "$DAY_BEFORE" ] && [ "$LAST_RUN" != "$YESTERDAY" ]; then
70
+ # Day before yesterday wasn't analyzed — catch up
71
+ if [ ! -f "$DEEP_SLEEP_DIR/$DAY_BEFORE-analysis.json" ]; then
72
+ log "*** CATCH-UP: $DAY_BEFORE was missed. Running now. ***"
73
+ run_analysis "$DAY_BEFORE" || log "Catch-up for $DAY_BEFORE failed."
69
74
  fi
70
75
  fi
71
76
 
72
- # --- Run today's analysis ---
73
- run_analysis "$TODAY"
77
+ # --- Run yesterday's analysis (main task — at 4:30 AM, today has no sessions yet) ---
78
+ run_analysis "$YESTERDAY"
74
79
 
75
- # Mark completion
76
- echo "$TODAY" > "$LAST_RUN_FILE"
80
+ # Mark completion with yesterday's date (what we actually analyzed)
81
+ echo "$YESTERDAY" > "$LAST_RUN_FILE"