nexo-brain 1.2.0 → 1.2.2
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 +7 -1
- package/package.json +1 -1
- package/src/hooks/session-start.sh +4 -1
- package/src/hooks/session-stop.sh +60 -30
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NEXO Brain — Your AI Gets a Brain
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/nexo-brain)
|
|
4
4
|
[](https://github.com/wazionapps/nexo/blob/main/benchmarks/locomo/results/)
|
|
5
5
|
[](https://github.com/snap-research/locomo/issues/33)
|
|
6
6
|
[](https://github.com/wazionapps/nexo/stargazers)
|
|
@@ -604,6 +604,12 @@ If NEXO Brain is useful to you, consider:
|
|
|
604
604
|
|
|
605
605
|
## Changelog
|
|
606
606
|
|
|
607
|
+
### v1.2.1 — Stop Hook Hotfix (2026-03-27)
|
|
608
|
+
- **Fix**: v1.2.0 deleted the flag on approve, causing infinite block loops if session didn't close immediately
|
|
609
|
+
- **Fix**: Removed TTL on flag — it persists until SessionStart cleans it up next session
|
|
610
|
+
- **New**: Trivial sessions (<5 meaningful tool calls) skip post-mortem entirely and approve immediately
|
|
611
|
+
- SessionStart hook now cleans up `.postmortem-complete` flag on session start
|
|
612
|
+
|
|
607
613
|
### v1.2.0 — Blocking Stop Hook (2026-03-27)
|
|
608
614
|
- **Fix**: Stop hook now uses `"decision": "block"` instead of `"approve"` to enforce post-mortem execution
|
|
609
615
|
- Previous behavior: hook injected `systemMessage` but AI had already responded — instructions were never processed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO \u2014 Cognitive co-operator for Claude Code. Atkinson-Shiffrin memory, semantic RAG, trust scoring, and metacognitive error prevention.",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,10 @@ NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
|
|
|
8
8
|
BRIEFING_FILE="$NEXO_HOME/coordination/session-briefing.txt"
|
|
9
9
|
MAX_AGE_SECONDS=3600 # 1 hour cache
|
|
10
10
|
|
|
11
|
-
mkdir -p "$NEXO_HOME/coordination"
|
|
11
|
+
mkdir -p "$NEXO_HOME/coordination" "$NEXO_HOME/operations"
|
|
12
|
+
|
|
13
|
+
# Clean up post-mortem flag from previous session
|
|
14
|
+
rm -f "$NEXO_HOME/operations/.postmortem-complete" 2>/dev/null
|
|
12
15
|
|
|
13
16
|
# If briefing exists and is less than 1 hour old, skip regeneration
|
|
14
17
|
if [ -f "$BRIEFING_FILE" ]; then
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# NEXO Stop hook (
|
|
2
|
+
# NEXO Stop hook (v7 — BLOCKING post-mortem with trivial session detection)
|
|
3
3
|
#
|
|
4
|
-
# v5 bug: used "
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
4
|
+
# v5 bug: used "approve" + systemMessage — AI never processed post-mortem.
|
|
5
|
+
# v6 bug: used "block" but deleted flag on approve — caused infinite block loop.
|
|
6
|
+
# Also had TTL on flag that expired between close attempts.
|
|
7
|
+
# v7 fix: trivial sessions (<5 tool calls) approve immediately.
|
|
8
|
+
# Non-trivial sessions block until post-mortem is done.
|
|
9
|
+
# Flag has NO TTL and is NOT deleted on approve.
|
|
10
|
+
# SessionStart hook cleans up the flag for the next session.
|
|
11
11
|
#
|
|
12
12
|
# Flow:
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
13
|
+
# Trivial session (quick question, <5 meaningful tool calls):
|
|
14
|
+
# → APPROVE immediately, no post-mortem needed
|
|
15
|
+
#
|
|
16
|
+
# Non-trivial session:
|
|
17
|
+
# 1. User closes → hook checks flag → not found → BLOCK
|
|
18
|
+
# 2. AI executes post-mortem → creates flag
|
|
19
|
+
# 3. User closes again → hook sees flag → APPROVE
|
|
20
|
+
# 4. Next session start → SessionStart hook deletes flag
|
|
17
21
|
set -euo pipefail
|
|
18
22
|
|
|
19
23
|
NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
|
|
20
24
|
NEXO_NAME="${NEXO_NAME:-NEXO}"
|
|
21
25
|
FLAG_FILE="$NEXO_HOME/operations/.postmortem-complete"
|
|
26
|
+
TODAY=$(date +%Y-%m-%d)
|
|
27
|
+
TOOL_LOG="$NEXO_HOME/operations/tool-logs/${TODAY}.jsonl"
|
|
22
28
|
|
|
23
29
|
# 0. Refresh diary draft with latest changes/decisions (best-effort)
|
|
24
30
|
python3 -c "
|
|
@@ -50,25 +56,51 @@ except Exception:
|
|
|
50
56
|
pass
|
|
51
57
|
" 2>/dev/null || true
|
|
52
58
|
|
|
53
|
-
# 1.
|
|
59
|
+
# 1. Detect trivial session — count meaningful tool calls from today's log
|
|
60
|
+
# A session with <5 tool calls (excluding Read/Grep/Glob/Bash/ToolSearch) is trivial
|
|
61
|
+
TOOL_COUNT=0
|
|
62
|
+
if [ -f "$TOOL_LOG" ]; then
|
|
63
|
+
TOOL_COUNT=$(python3 -c "
|
|
64
|
+
import json, sys
|
|
65
|
+
count = 0
|
|
66
|
+
for line in open('$TOOL_LOG'):
|
|
67
|
+
try:
|
|
68
|
+
d = json.loads(line)
|
|
69
|
+
t = d.get('tool_name', '')
|
|
70
|
+
if t and t not in ('Read', 'Grep', 'Glob', 'Bash', 'ToolSearch'):
|
|
71
|
+
count += 1
|
|
72
|
+
except:
|
|
73
|
+
pass
|
|
74
|
+
print(count)
|
|
75
|
+
" 2>/dev/null || echo "0")
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Trivial session → approve immediately, write minimal buffer, skip post-mortem
|
|
79
|
+
if [ "$TOOL_COUNT" -lt 5 ]; then
|
|
80
|
+
BUFFER="$NEXO_HOME/brain/session_buffer.jsonl"
|
|
81
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S")
|
|
82
|
+
mkdir -p "$(dirname "$BUFFER")"
|
|
83
|
+
echo "{\"ts\":\"$TIMESTAMP\",\"tasks\":[\"trivial session\"],\"decisions\":[],\"user_patterns\":[],\"files_modified\":[],\"errors_resolved\":[],\"self_critique\":\"trivial session — no post-mortem needed\",\"mood\":\"neutral\",\"source\":\"hook-trivial\"}" >> "$BUFFER" 2>/dev/null
|
|
84
|
+
|
|
85
|
+
cat << 'HOOKEOF'
|
|
86
|
+
{
|
|
87
|
+
"decision": "approve"
|
|
88
|
+
}
|
|
89
|
+
HOOKEOF
|
|
90
|
+
exit 0
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# 2. Non-trivial session — check if post-mortem was already completed
|
|
94
|
+
# Flag has NO TTL — it persists until SessionStart cleans it up next session.
|
|
95
|
+
# IMPORTANT: do NOT delete flag here — that causes an infinite block loop
|
|
96
|
+
# if the session doesn't close immediately after approve.
|
|
54
97
|
POSTMORTEM_DONE=false
|
|
55
98
|
if [ -f "$FLAG_FILE" ]; then
|
|
56
|
-
|
|
57
|
-
import os, time
|
|
58
|
-
try:
|
|
59
|
-
age = time.time() - os.path.getmtime('$FLAG_FILE')
|
|
60
|
-
print('recent' if age < 120 else 'stale')
|
|
61
|
-
except:
|
|
62
|
-
print('stale')
|
|
63
|
-
" 2>/dev/null || echo "stale")
|
|
64
|
-
if [ "$FLAG_AGE" = "recent" ]; then
|
|
65
|
-
POSTMORTEM_DONE=true
|
|
66
|
-
fi
|
|
99
|
+
POSTMORTEM_DONE=true
|
|
67
100
|
fi
|
|
68
101
|
|
|
69
102
|
if [ "$POSTMORTEM_DONE" = true ]; then
|
|
70
103
|
# Post-mortem was done — allow session to close
|
|
71
|
-
rm -f "$FLAG_FILE" 2>/dev/null
|
|
72
104
|
cat << 'HOOKEOF'
|
|
73
105
|
{
|
|
74
106
|
"decision": "approve"
|
|
@@ -76,16 +108,15 @@ if [ "$POSTMORTEM_DONE" = true ]; then
|
|
|
76
108
|
HOOKEOF
|
|
77
109
|
else
|
|
78
110
|
# Post-mortem NOT done — BLOCK session close and inject instructions
|
|
79
|
-
# Uses "reason" field which Claude Code shows to the AI as context
|
|
80
111
|
cat << HOOKEOF
|
|
81
112
|
{
|
|
82
113
|
"decision": "block",
|
|
83
|
-
"reason": "STOP HOOK — MANDATORY POST-MORTEM before ending (do NOT ask permission, do NOT skip):\n\n## 1. SELF-CRITIQUE (MANDATORY — write to session diary)\nAnswer these questions in the self_critique field of nexo_session_diary_write:\n- Did the user have to ask me for something I should have detected or done on my own?\n- Did I wait for the user to tell me something I could have verified proactively?\n- Are there systems/states I can check next session without being asked?\n- Did I repeat an error that already had a registered learning?\n- What would I do differently if I repeated this session?\nIf any answer is YES — write the specific rule that would prevent repetition.\nIf the session was flawless, write 'No self-critique — clean session.'\n\n## 2. SESSION BUFFER\nIf the session was NOT trivial, append ONE JSON line to ${NEXO_HOME}/brain/session_buffer.jsonl:\n{\"ts\":\"YYYY-MM-DDTHH:MM:SS\",\"tasks\":[...],\"decisions\":[...],\"user_patterns\":[...],\"files_modified\":[...],\"errors_resolved\":[...],\"self_critique\":\"short summary\",\"mood\":\"focused|impatient|exploratory|frustrated|satisfied|neutral\",\"source\":\"claude\"}\n\n## 3. FOLLOWUPS\nIf there were deploys/cron changes/fixes — nexo_followup_create with verification date.\n\n## 4. PROACTIVE SEEDS\nWhat can I leave prepared so the next session starts doing useful work without the user asking?\n\n## 5. MARK COMPLETE\nWhen ALL of the above is done, run:\nbash -c 'mkdir -p ${NEXO_HOME}/operations && date +%s > ${NEXO_HOME}/operations/.postmortem-complete'\
|
|
114
|
+
"reason": "STOP HOOK — MANDATORY POST-MORTEM before ending (do NOT ask permission, do NOT skip):\n\n## 1. SELF-CRITIQUE (MANDATORY — write to session diary)\nAnswer these questions in the self_critique field of nexo_session_diary_write:\n- Did the user have to ask me for something I should have detected or done on my own?\n- Did I wait for the user to tell me something I could have verified proactively?\n- Are there systems/states I can check next session without being asked?\n- Did I repeat an error that already had a registered learning?\n- What would I do differently if I repeated this session?\nIf any answer is YES — write the specific rule that would prevent repetition.\nIf the session was flawless, write 'No self-critique — clean session.'\n\n## 2. SESSION BUFFER\nIf the session was NOT trivial, append ONE JSON line to ${NEXO_HOME}/brain/session_buffer.jsonl:\n{\"ts\":\"YYYY-MM-DDTHH:MM:SS\",\"tasks\":[...],\"decisions\":[...],\"user_patterns\":[...],\"files_modified\":[...],\"errors_resolved\":[...],\"self_critique\":\"short summary\",\"mood\":\"focused|impatient|exploratory|frustrated|satisfied|neutral\",\"source\":\"claude\"}\n\n## 3. FOLLOWUPS\nIf there were deploys/cron changes/fixes — nexo_followup_create with verification date.\n\n## 4. PROACTIVE SEEDS\nWhat can I leave prepared so the next session starts doing useful work without the user asking?\n\n## 5. MARK COMPLETE\nWhen ALL of the above is done, run:\nbash -c 'mkdir -p ${NEXO_HOME}/operations && date +%s > ${NEXO_HOME}/operations/.postmortem-complete'\nThe user will close again and the hook will approve.\n\nIMPORTANT: Do NOT say goodbye, do NOT say goodnight or any farewell. Just execute the steps and mark complete."
|
|
84
115
|
}
|
|
85
116
|
HOOKEOF
|
|
86
117
|
fi
|
|
87
118
|
|
|
88
|
-
#
|
|
119
|
+
# 3. Direct session buffer fallback (runs for non-trivial sessions)
|
|
89
120
|
BUFFER="$NEXO_HOME/brain/session_buffer.jsonl"
|
|
90
121
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S")
|
|
91
122
|
|
|
@@ -132,8 +163,7 @@ except:
|
|
|
132
163
|
echo "{\"ts\":\"$TIMESTAMP\",\"tasks\":[\"session ended\"],\"decisions\":[],\"user_patterns\":[],\"files_modified\":[],\"errors_resolved\":[],\"self_critique\":\"hook-fallback, no self-critique captured\",\"mood\":\"unknown\",\"session_end_mode\":\"$ADAPTIVE_MODE\",\"source\":\"hook-fallback\"}" >> "$BUFFER" 2>/dev/null
|
|
133
164
|
fi
|
|
134
165
|
|
|
135
|
-
#
|
|
136
|
-
# Check if buffer has >=3 sessions AND last reflection was >4h ago
|
|
166
|
+
# 4. Intra-day reflection trigger
|
|
137
167
|
REFLECTION_SCRIPT="$NEXO_HOME/scripts/nexo-reflection.py"
|
|
138
168
|
REFLECTION_STATE="$NEXO_HOME/coordination/reflection-log.json"
|
|
139
169
|
TRIGGER_THRESHOLD=3
|