nexo-brain 7.23.8 → 7.23.11
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/auto_update.py +17 -1
- package/src/dashboard/templates/chat.html +2 -2
- package/src/doctor/planes.py +21 -21
- package/src/plugins/cards.py +7 -7
- package/src/r14_correction_learning.py +5 -5
- package/src/r15_project_context.py +4 -4
- package/src/r16_declared_done.py +4 -4
- package/src/r17_promise_debt.py +5 -5
- package/src/r18_followup_autocomplete.py +5 -5
- package/src/r19_project_grep.py +4 -4
- package/src/r20_constant_change.py +4 -4
- package/src/r21_legacy_path.py +3 -3
- package/src/r22_personal_script.py +4 -4
- package/src/r23_ssh_without_atlas.py +4 -4
- package/src/r24_stale_memory.py +4 -4
- package/src/r25_nora_maria_read_only.py +6 -6
- package/src/runtime_versioning.py +30 -12
- package/src/skills/run-nexo-audit-phase/guide.md +33 -33
- package/src/skills/run-nexo-audit-phase/skill.json +15 -15
- package/src/skills/run-nexo-core-fix-cycle/guide.md +11 -11
- package/src/skills/run-nexo-core-fix-cycle/skill.json +5 -5
- package/templates/core-prompts/t4-r15-project-context-gate.md +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.23.
|
|
3
|
+
"version": "7.23.11",
|
|
4
4
|
"description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
[Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
|
|
20
20
|
|
|
21
|
-
Version `7.23.
|
|
21
|
+
Version `7.23.11` is the current packaged-runtime line. Patch over v7.23.10 - older installed runtimes can update safely even when `cognitive_paths.py` has not been synced yet.
|
|
22
|
+
|
|
23
|
+
Previously in `7.23.6`: patch over v7.23.5 - `nexo update` clears safe legacy `cognitive.db` shadows and keeps superseded archives under runtime backup retention.
|
|
22
24
|
|
|
23
25
|
Previously in `7.23.5`: patch over v7.23.4 - `nexo update` keeps external CLI maintenance summary copy in English.
|
|
24
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.23.
|
|
3
|
+
"version": "7.23.11",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
|
|
6
6
|
"homepage": "https://nexo-brain.com",
|
package/src/auto_update.py
CHANGED
|
@@ -32,7 +32,23 @@ except ModuleNotFoundError as exc:
|
|
|
32
32
|
sys.path.insert(0, core_path)
|
|
33
33
|
from product_mode import enforce_desktop_product_contract
|
|
34
34
|
from runtime_home import export_resolved_nexo_home, managed_nexo_home
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from cognitive_paths import cleanup_legacy_cognitive_db_artifacts
|
|
38
|
+
except ModuleNotFoundError as exc:
|
|
39
|
+
if getattr(exc, "name", "") != "cognitive_paths":
|
|
40
|
+
raise
|
|
41
|
+
|
|
42
|
+
# Older installed runtimes may import this newer auto_update.py before
|
|
43
|
+
# cognitive_paths.py has been copied into place. Keep update importable so
|
|
44
|
+
# the sync can finish and deliver the missing module.
|
|
45
|
+
def cleanup_legacy_cognitive_db_artifacts(*, dry_run: bool = False) -> dict:
|
|
46
|
+
return {
|
|
47
|
+
"ok": True,
|
|
48
|
+
"skipped": True,
|
|
49
|
+
"reason": "cognitive_paths_unavailable_until_runtime_sync",
|
|
50
|
+
"dry_run": dry_run,
|
|
51
|
+
}
|
|
36
52
|
|
|
37
53
|
try:
|
|
38
54
|
from tree_hygiene import is_duplicate_artifact_name
|
|
@@ -331,14 +331,14 @@ async function sendMessage() {
|
|
|
331
331
|
const data = await res.json();
|
|
332
332
|
chatHistory.push({
|
|
333
333
|
role: 'nexo',
|
|
334
|
-
content: data.answer || '
|
|
334
|
+
content: data.answer || 'No response.',
|
|
335
335
|
data: data.data || null,
|
|
336
336
|
query_type: data.query_type || null
|
|
337
337
|
});
|
|
338
338
|
}
|
|
339
339
|
} catch (err) {
|
|
340
340
|
hideTyping();
|
|
341
|
-
chatHistory.push({ role: 'nexo', content: `
|
|
341
|
+
chatHistory.push({ role: 'nexo', content: `Connection error: ${err.message}` });
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
isWaiting = false;
|
package/src/doctor/planes.py
CHANGED
|
@@ -6,24 +6,24 @@ from doctor.models import DoctorCheck
|
|
|
6
6
|
|
|
7
7
|
VALID_DIAGNOSTIC_PLANES = {
|
|
8
8
|
"product_public": {
|
|
9
|
-
"label": "
|
|
10
|
-
"use": "release contracts,
|
|
9
|
+
"label": "public product",
|
|
10
|
+
"use": "release contracts, published artifacts, compare/, docs, and public repo surfaces",
|
|
11
11
|
},
|
|
12
12
|
"runtime_personal": {
|
|
13
|
-
"label": "runtime
|
|
14
|
-
"use": "~/.nexo, scripts
|
|
13
|
+
"label": "personal runtime",
|
|
14
|
+
"use": "~/.nexo, personal scripts, followups, reminders, and operator work habits",
|
|
15
15
|
},
|
|
16
16
|
"installation_live": {
|
|
17
|
-
"label": "
|
|
18
|
-
"use": "runtime
|
|
17
|
+
"label": "live installation",
|
|
18
|
+
"use": "installed runtime, active hooks, connected clients, cron sync, and local installation parity",
|
|
19
19
|
},
|
|
20
20
|
"database_real": {
|
|
21
|
-
"label": "
|
|
22
|
-
"use": "SQLite/MySQL
|
|
21
|
+
"label": "real database",
|
|
22
|
+
"use": "real SQLite/MySQL, rows, schema, debts, sessions, and persisted evidence",
|
|
23
23
|
},
|
|
24
24
|
"cooperator": {
|
|
25
|
-
"label": "co-
|
|
26
|
-
"use": "
|
|
25
|
+
"label": "co-operator",
|
|
26
|
+
"use": "agent behavior, protocol, communication, and assistant decisions",
|
|
27
27
|
},
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -53,17 +53,17 @@ def diagnostic_plane_preflight(plane: str = "") -> tuple[str, DoctorCheck | None
|
|
|
53
53
|
tier="orchestrator",
|
|
54
54
|
status="critical",
|
|
55
55
|
severity="error",
|
|
56
|
-
summary=f"
|
|
56
|
+
summary=f"Unknown diagnostic plane: {raw_plane}",
|
|
57
57
|
evidence=[
|
|
58
|
-
f"planes
|
|
59
|
-
"
|
|
58
|
+
f"valid planes: {options}",
|
|
59
|
+
"Use `runtime_personal` for ~/.nexo and runtime habits; `installation_live` for hooks/clients/installation; `database_real` for real rows and schema.",
|
|
60
60
|
],
|
|
61
61
|
repair_plan=[
|
|
62
|
-
"
|
|
63
|
-
"
|
|
62
|
+
"Run `nexo_doctor` or `nexo doctor` again with `plane='runtime_personal'`, `plane='installation_live'`, or `plane='database_real'`.",
|
|
63
|
+
"If the issue belongs to the public product or the co-operator, use the correct surface instead of NEXO Doctor.",
|
|
64
64
|
],
|
|
65
65
|
escalation_prompt=(
|
|
66
|
-
"
|
|
66
|
+
"The selected plane does not exist. Repeat the diagnosis with a valid plane to avoid mixing runtime, installation, real DB, or non-doctor surfaces."
|
|
67
67
|
),
|
|
68
68
|
)
|
|
69
69
|
|
|
@@ -74,17 +74,17 @@ def diagnostic_plane_preflight(plane: str = "") -> tuple[str, DoctorCheck | None
|
|
|
74
74
|
tier="orchestrator",
|
|
75
75
|
status="degraded",
|
|
76
76
|
severity="warn",
|
|
77
|
-
summary=f"NEXO Doctor
|
|
77
|
+
summary=f"NEXO Doctor is not the correct surface for the {plane_info['label']} plane",
|
|
78
78
|
evidence=[
|
|
79
79
|
f"plane: {clean_plane}",
|
|
80
|
-
f"
|
|
80
|
+
f"this plane is better diagnosed from: {plane_info['use']}",
|
|
81
81
|
],
|
|
82
82
|
repair_plan=[
|
|
83
|
-
"
|
|
84
|
-
"
|
|
83
|
+
"If you want to diagnose runtime/installation/DB, rerun the doctor with the correct plane.",
|
|
84
|
+
"If the issue belongs to the public product or the co-operator, use release checks, repo checks, or protocol/session tools instead of Doctor.",
|
|
85
85
|
],
|
|
86
86
|
escalation_prompt=(
|
|
87
|
-
"
|
|
87
|
+
"The selected plane does not belong to the runtime doctor. Change the plane or tool before continuing so technical diagnosis is not mixed with product or agent behavior."
|
|
88
88
|
),
|
|
89
89
|
)
|
|
90
90
|
|
package/src/plugins/cards.py
CHANGED
|
@@ -47,8 +47,8 @@ def _api_base() -> str:
|
|
|
47
47
|
return raw.strip().rstrip("/") or DEFAULT_API_BASE
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def _normalize_locale(locale: str = "
|
|
51
|
-
return "
|
|
50
|
+
def _normalize_locale(locale: str = "en") -> str:
|
|
51
|
+
return "es" if str(locale or "").lower().startswith("es") else "en"
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def _shared_auth_candidates() -> list[Path]:
|
|
@@ -126,12 +126,12 @@ def _decode_body(raw: bytes) -> dict[str, Any]:
|
|
|
126
126
|
return {"raw": raw.decode("utf-8", errors="replace")[:1000]}
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
def _request_json(method: str, path: str, *, body: dict[str, Any] | None = None, locale: str = "
|
|
129
|
+
def _request_json(method: str, path: str, *, body: dict[str, Any] | None = None, locale: str = "en") -> dict[str, Any]:
|
|
130
130
|
token = _read_token()
|
|
131
131
|
if not token:
|
|
132
132
|
return _error(
|
|
133
133
|
"not_authenticated",
|
|
134
|
-
"No
|
|
134
|
+
"No NEXO Desktop session is available to fetch protocol cards.",
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
data = json.dumps(body or {}, ensure_ascii=False).encode("utf-8") if body is not None else None
|
|
@@ -169,13 +169,13 @@ def _request_json(method: str, path: str, *, body: dict[str, Any] | None = None,
|
|
|
169
169
|
return _error("network_error", str(exc))
|
|
170
170
|
|
|
171
171
|
|
|
172
|
-
def handle_card_catalog(locale: str = "
|
|
172
|
+
def handle_card_catalog(locale: str = "en") -> str:
|
|
173
173
|
"""Return the visible official protocol card catalog. Never includes protocols."""
|
|
174
174
|
params = urllib.parse.urlencode({"locale": _normalize_locale(locale)})
|
|
175
175
|
return _json(_request_json("GET", f"/api/cards/catalog?{params}", locale=locale))
|
|
176
176
|
|
|
177
177
|
|
|
178
|
-
def handle_card_get(slug: str, locale: str = "
|
|
178
|
+
def handle_card_get(slug: str, locale: str = "en") -> str:
|
|
179
179
|
"""Fetch one official protocol card, including protocol text, by slug."""
|
|
180
180
|
clean_slug = str(slug or "").strip()
|
|
181
181
|
if not clean_slug:
|
|
@@ -189,7 +189,7 @@ def handle_card_match(
|
|
|
189
189
|
query: str,
|
|
190
190
|
limit: int = 5,
|
|
191
191
|
include_protocol: bool = True,
|
|
192
|
-
locale: str = "
|
|
192
|
+
locale: str = "en",
|
|
193
193
|
category: str = "",
|
|
194
194
|
business_type: str = "",
|
|
195
195
|
) -> str:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""r14_correction_learning — detect user corrections and demand a learning_add.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase C (Layer 2) item R14. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
IF the last user message -> cognitive_sentiment.is_correction = true
|
|
6
|
+
OR valence < -0.4
|
|
7
|
+
AND nexo_learning_add does NOT appear in the next 3 tool calls
|
|
8
|
+
THEN inject the obligation.
|
|
9
9
|
|
|
10
10
|
Implementation contract:
|
|
11
11
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r15_project_context — demand project context before editing a project path.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R15. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the user message mentions a registered entity with type=project
|
|
6
|
+
AND the session has no nexo_recall(project) nor atlas read
|
|
7
|
+
THEN inject the obligation.
|
|
8
8
|
|
|
9
9
|
This module exposes pure helpers:
|
|
10
10
|
|
package/src/r16_declared_done.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r16_declared_done — detect "I'm done" outputs without nexo_task_close.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase C (Layer 2) item R16. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the classifier detects that the last output claims task completion
|
|
6
|
+
AND there is an open protocol task
|
|
7
|
+
THEN inject the task_close-with-evidence obligation.
|
|
8
8
|
|
|
9
9
|
Exposes detect_declared_done(assistant_text, classifier=None) → bool and
|
|
10
10
|
the reminder prompt template. The window-and-state tracking lives in
|
package/src/r17_promise_debt.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r17_promise_debt — detect assistant promises that were not executed.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R17. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the classifier detects a future-action promise in user-facing output
|
|
6
|
+
AND the next 2 turns have no relevant tool calls
|
|
7
|
+
THEN flag promise_debt + reminder.
|
|
8
8
|
|
|
9
9
|
Exposes detect_promise(text, classifier) → bool. State (promise window
|
|
10
10
|
countdown) lives in the caller — mirrors the R14 / R16 pattern.
|
|
@@ -13,7 +13,7 @@ Classifier path is the same as R14 / R16:
|
|
|
13
13
|
semantic_router decision_kind ``r17_promise_debt``. Fail-closed on any
|
|
14
14
|
unavailable backend (no promise flagged rather than a false positive).
|
|
15
15
|
|
|
16
|
-
Mirror: nexo-desktop/lib/r17-promise-debt.js (bundled with
|
|
16
|
+
Mirror: nexo-desktop/lib/r17-promise-debt.js (bundled with Phase D JS
|
|
17
17
|
twins at the end of the tranche).
|
|
18
18
|
"""
|
|
19
19
|
from __future__ import annotations
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"""r18_followup_autocomplete — suggest followup_complete retroactively.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R18. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
On session open: load active followups
|
|
6
|
+
IF the executed action matches an active followup (>70%)
|
|
7
|
+
THEN suggest followup_complete.
|
|
8
8
|
|
|
9
9
|
R18 is a SUGGESTION rule (not a block). The enforcer emits a single
|
|
10
10
|
reminder per followup hit per turn, and operators / Cortex decide
|
|
11
11
|
whether to actually call nexo_followup_complete.
|
|
12
12
|
|
|
13
13
|
Reuses the Jaccard matcher from tools_reminders_crud.find_completable_
|
|
14
|
-
followups (
|
|
14
|
+
followups (Phase B R04 helper) rather than duplicating the matching
|
|
15
15
|
logic. The trigger signal is the tool_name + tool_input of the agent's
|
|
16
16
|
actions — we build a one-shot "action description" string from those
|
|
17
17
|
and run the R04 matcher over it.
|
package/src/r19_project_grep.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r19_project_grep — require Grep before Write on project paths with require_grep flag.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R19. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the intent is Write on a type=project entity path with require_grep
|
|
6
|
+
AND there was no prior Grep for the symbol/function
|
|
7
|
+
THEN inject the grep obligation.
|
|
8
8
|
|
|
9
9
|
Pure decision module — state (projects list, recent_tool_records) is
|
|
10
10
|
owned by the caller (HeadlessEnforcer).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r20_constant_change — demand grep-all-usages before changing a constant.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R20. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the classifier detects that Edit changes a shared constant/global/config
|
|
6
|
+
AND there was no Grep for the symbol
|
|
7
|
+
THEN inject an obligation to grep ALL usages.
|
|
8
8
|
|
|
9
9
|
Decision logic is split in two:
|
|
10
10
|
|
package/src/r21_legacy_path.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r21_legacy_path — warn when a command / edit touches a legacy path.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R21. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
IF Bash or Edit intent path contains an entity_list entry
|
|
6
6
|
type=legacy_path
|
|
7
|
-
|
|
7
|
+
THEN inject the canonical reminder.
|
|
8
8
|
|
|
9
9
|
Pure decision module. Legacy-path entities are seeded at `nexo init`
|
|
10
10
|
from src/presets/entities_universal.json (the ~/claude → ~/.nexo mapping).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r22_personal_script — demand context lookup before creating a personal script.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R22. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the intent is nexo_personal_script_create OR Write under scripts/
|
|
6
|
+
AND there was no personal_scripts_list + skill_match + learning_search
|
|
7
|
+
THEN inject the obligation.
|
|
8
8
|
|
|
9
9
|
R22 fires BEFORE introducing a new personal script to make sure the
|
|
10
10
|
agent first checked:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r23_ssh_without_atlas — demand atlas lookup before SSHing to an unknown host.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R23. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF Bash intent uses ssh|scp|rsync|curl toward a host
|
|
6
|
+
AND the host is not in entity_list type=host
|
|
7
|
+
THEN inject the atlas-read obligation.
|
|
8
8
|
|
|
9
9
|
Reuses the host-extraction primitive from r25 (imported lazily to avoid
|
|
10
10
|
a hard dependency — same mirror is provided on the JS side via the r25
|
package/src/r24_stale_memory.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""r24_stale_memory — warn when a stale memory is cited without verification.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase D item R24. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
IF the last 3 turns cited recall/memory data with age>7
|
|
6
|
+
AND there was no fresh verification tool call
|
|
7
|
+
THEN warn.
|
|
8
8
|
|
|
9
9
|
Implementation approach:
|
|
10
10
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"""r25_nora_maria_read_only — block destructive SSH/scp/rsync to read-only hosts.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Phase 2 Protocol Enforcer Phase C (Layer 2) item R25. Plan doc 1 reads:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
IF Bash "ssh" intent targets a host with entity.access_mode=read_only
|
|
6
|
+
AND the command includes destructive verbs (rm/mv/>/>>/sed -i)
|
|
7
|
+
AND the user message contains no explicit permission
|
|
8
|
+
THEN BLOCK + ask for confirmation.
|
|
9
9
|
|
|
10
10
|
The enforcer runs in observer mode (headless subprocess, Desktop
|
|
11
11
|
stream wrapper), so "blocking" in practice means enqueueing a hard,
|
|
12
12
|
prominent injection that names the host and the destructive verb.
|
|
13
|
-
The MCP-side guard (
|
|
13
|
+
The MCP-side guard (Layer 1 learnings #283 / #336 / #358) and the
|
|
14
14
|
system-prompt rule R32 keep the agent from actually issuing the
|
|
15
15
|
command when it honours the reminder.
|
|
16
16
|
|
|
@@ -890,15 +890,28 @@ def _mcp_client_readiness(
|
|
|
890
890
|
) -> dict:
|
|
891
891
|
generation = runtime_generation(installed_version_value, installed_fp, str(active_runtime_root()))
|
|
892
892
|
process_fp = str(state.get("process_fingerprint") or "").strip()
|
|
893
|
+
service_fp = str(service_status.get("runtime_fingerprint") or "").strip()
|
|
894
|
+
effective_process_fp = process_fp or service_fp
|
|
893
895
|
service_ok = bool(service_status.get("ok", True))
|
|
894
896
|
fingerprint_ready = (
|
|
895
897
|
bool(installed_fp)
|
|
896
|
-
and bool(
|
|
897
|
-
and
|
|
898
|
-
and installed_fp ==
|
|
898
|
+
and bool(effective_process_fp)
|
|
899
|
+
and effective_process_fp != "unknown"
|
|
900
|
+
and installed_fp == effective_process_fp
|
|
901
|
+
)
|
|
902
|
+
marker_recoverable_reason = str(state.get("reason") or "") in {
|
|
903
|
+
"marker_required",
|
|
904
|
+
"process_fingerprint_missing",
|
|
905
|
+
}
|
|
906
|
+
marker_recoverable_for_client = (
|
|
907
|
+
bool(client)
|
|
908
|
+
and bool(state.get("restart_required"))
|
|
909
|
+
and marker_recoverable_reason
|
|
910
|
+
and fingerprint_ready
|
|
911
|
+
and service_ok
|
|
899
912
|
)
|
|
900
913
|
global_ready = (
|
|
901
|
-
not bool(state.get("restart_required"))
|
|
914
|
+
(not bool(state.get("restart_required")) or marker_recoverable_for_client)
|
|
902
915
|
and fingerprint_ready
|
|
903
916
|
and service_ok
|
|
904
917
|
)
|
|
@@ -906,13 +919,13 @@ def _mcp_client_readiness(
|
|
|
906
919
|
global_reason = "runtime_service_unavailable"
|
|
907
920
|
elif not installed_fp:
|
|
908
921
|
global_reason = "installed_fingerprint_missing"
|
|
909
|
-
elif not
|
|
922
|
+
elif not effective_process_fp or effective_process_fp == "unknown":
|
|
910
923
|
global_reason = "process_fingerprint_missing"
|
|
911
|
-
elif installed_fp !=
|
|
924
|
+
elif installed_fp != effective_process_fp:
|
|
912
925
|
global_reason = "process_fingerprint_mismatch"
|
|
913
926
|
else:
|
|
914
927
|
global_reason = "ready"
|
|
915
|
-
if state.get("restart_required"):
|
|
928
|
+
if state.get("restart_required") and not marker_recoverable_for_client:
|
|
916
929
|
return {
|
|
917
930
|
"runtime_generation": generation,
|
|
918
931
|
"global_ready": False,
|
|
@@ -1003,6 +1016,11 @@ def build_mcp_status(*, client: str = "") -> dict:
|
|
|
1003
1016
|
service_status=service_status,
|
|
1004
1017
|
)
|
|
1005
1018
|
client_states = read_mcp_client_states()
|
|
1019
|
+
service_fp = str(service_status.get("runtime_fingerprint") or "").strip()
|
|
1020
|
+
effective_process_fp = process_fp or service_fp
|
|
1021
|
+
restart_required = bool(state["restart_required"]) and not bool(
|
|
1022
|
+
readiness["client_ready"]
|
|
1023
|
+
)
|
|
1006
1024
|
return {
|
|
1007
1025
|
"ok": True,
|
|
1008
1026
|
"schema_version": MCP_STATUS_SCHEMA_VERSION,
|
|
@@ -1013,14 +1031,14 @@ def build_mcp_status(*, client: str = "") -> dict:
|
|
|
1013
1031
|
"process_fingerprint": process_fp,
|
|
1014
1032
|
"fingerprint_match": (
|
|
1015
1033
|
bool(installed_fp)
|
|
1016
|
-
and bool(
|
|
1017
|
-
and
|
|
1018
|
-
and installed_fp ==
|
|
1034
|
+
and bool(effective_process_fp)
|
|
1035
|
+
and effective_process_fp != "unknown"
|
|
1036
|
+
and installed_fp == effective_process_fp
|
|
1019
1037
|
),
|
|
1020
1038
|
"active_runtime_root": str(active_runtime_root()),
|
|
1021
1039
|
"active_runtime_version": read_version_for_path(active_runtime_root()),
|
|
1022
|
-
"restart_required":
|
|
1023
|
-
"reason": state["reason"],
|
|
1040
|
+
"restart_required": restart_required,
|
|
1041
|
+
"reason": state["reason"] if restart_required else "",
|
|
1024
1042
|
"client_action": readiness["client_action"],
|
|
1025
1043
|
"reason_code": readiness["reason_code"],
|
|
1026
1044
|
"global_ready": bool(readiness["global_ready"]),
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
# Run NEXO Audit Phase
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this skill when a NEXO audit phase must be run and the bottleneck is deciding the `evolution_apply` scope and starting a batch of items with empirical discipline.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
1.
|
|
7
|
-
- repo/runtime
|
|
8
|
-
- DB
|
|
9
|
-
-
|
|
10
|
-
- tests
|
|
11
|
-
2.
|
|
12
|
-
- Francisco
|
|
13
|
-
- NEXO
|
|
14
|
-
-
|
|
15
|
-
3.
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
4.
|
|
20
|
-
- `grep + read`
|
|
21
|
-
- SQL/schema
|
|
22
|
-
- AST/tests/imports/logs
|
|
23
|
-
-
|
|
24
|
-
5.
|
|
5
|
+
## Steps
|
|
6
|
+
1. Open `goal + workflow + task` and establish the real surface before interpreting the report:
|
|
7
|
+
- active repo/runtime
|
|
8
|
+
- real DB
|
|
9
|
+
- update mechanism
|
|
10
|
+
- tests and git status
|
|
11
|
+
2. Set the autonomy rule before starting:
|
|
12
|
+
- Francisco does not want one-by-one checkpoints for mechanical work
|
|
13
|
+
- NEXO creates branches, PRs, merges, and reports afterward with evidence
|
|
14
|
+
- only a huge architectural blast radius deserves a checkpoint
|
|
15
|
+
3. Treat `evolution_apply` as a technical implementation decision, not as human permission:
|
|
16
|
+
- the apply path already exists through `evolution_log` + `_apply_accepted_proposals`
|
|
17
|
+
- sandbox/snapshot/rollback protects materialization of the accepted change
|
|
18
|
+
- do not duplicate that mechanism in deep sleep or the audit runner
|
|
19
|
+
4. Launch empirical verification of all items in parallel:
|
|
20
|
+
- `grep + read` over code
|
|
21
|
+
- real SQL/schema
|
|
22
|
+
- AST/tests/imports/logs when applicable
|
|
23
|
+
- assume FP until evidence contradicts it
|
|
24
|
+
5. Classify each item:
|
|
25
25
|
- `real_gap`
|
|
26
|
-
- `
|
|
26
|
+
- `near_fp`
|
|
27
27
|
- `fp`
|
|
28
|
-
6.
|
|
29
|
-
7.
|
|
28
|
+
6. Order only `real_gap` items by risk/blast radius and execute them with an isolated worktree if they touch core.
|
|
29
|
+
7. For each `real_gap`:
|
|
30
30
|
- `guard_check`
|
|
31
31
|
- `track`
|
|
32
|
-
- branch
|
|
33
|
-
-
|
|
34
|
-
- tests
|
|
32
|
+
- dedicated branch
|
|
33
|
+
- minimal implementation
|
|
34
|
+
- adjacent tests
|
|
35
35
|
- PR + auto-merge squash
|
|
36
|
-
-
|
|
37
|
-
8.
|
|
38
|
-
9.
|
|
36
|
+
- continue to the next item without waiting for CI unless there is a real blocker
|
|
37
|
+
8. For `fp` or `near_fp`, capture a learning/reusable pattern instead of reimplementing.
|
|
38
|
+
9. Close the phase with real evidence: PRs, tests, merge status, and verification results.
|
|
39
39
|
|
|
40
40
|
## Gotchas
|
|
41
|
-
- Learning #198:
|
|
42
|
-
- `apply_findings.py`
|
|
43
|
-
-
|
|
41
|
+
- Learning #198: do not confuse "how NEXO works" with "what evolution_apply may apply". The first is already settled: full autonomy.
|
|
42
|
+
- `apply_findings.py` already stages `code_change` in `evolution_log`; `nexo-evolution-run.py` already consumes `accepted` with sandbox/snapshot/rollback. If the item asks for that, first verify whether it already exists.
|
|
43
|
+
- In Phase 1+2 the automated audit overestimated about 70% of gaps. If there is no hard evidence, do not open code.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "SK-RUN-NEXO-AUDIT-PHASE",
|
|
3
3
|
"name": "Run NEXO Audit Phase",
|
|
4
|
-
"description": "Workflow
|
|
4
|
+
"description": "Workflow for running a NEXO audit phase with full autonomy and empirical verification. Covers the recurring pattern of deciding the evolution_apply scope and starting a batch of items without manual checkpoints.",
|
|
5
5
|
"level": "published",
|
|
6
6
|
"mode": "guide",
|
|
7
7
|
"source_kind": "core",
|
|
@@ -17,26 +17,26 @@
|
|
|
17
17
|
],
|
|
18
18
|
"trigger_patterns": [
|
|
19
19
|
"evolution_apply sandbox scope",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
20
|
+
"phase 2 item 1",
|
|
21
|
+
"start empirical verification",
|
|
22
|
+
"run nexo audit phase",
|
|
23
23
|
"audit phase nexo",
|
|
24
24
|
"7 items audit"
|
|
25
25
|
],
|
|
26
26
|
"steps": [
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
27
|
+
"Open the goal, workflow, and task before touching the audit; resolve the real repo/runtime, real DB, tests, and git status before interpreting the report.",
|
|
28
|
+
"Set the autonomy rule: NEXO creates branches, PRs, merges, and periodic progress reports; do not ask Francisco for one-by-one checkpoints for mechanical work.",
|
|
29
|
+
"For `evolution_apply`, separate two planes: the sandbox materializes/applies accepted changes with snapshot/rollback; it is not a brake on the agent's autonomous work mode.",
|
|
30
|
+
"Launch empirical verification of ALL items in parallel: grep+read, real SQL/schema, AST/tests, logs. Start from the FP hypothesis until evidence says otherwise.",
|
|
31
|
+
"Classify each item as `real_gap`, `near_fp`, or `fp`, and order only real items by blast radius/risk.",
|
|
32
|
+
"If core must be touched, use an isolated worktree; for each real item: guard_check -> track -> branch -> implement -> adjacent tests -> PR -> auto-merge squash.",
|
|
33
|
+
"For FP or near-FP items, capture a learning or adjust the reusable pattern instead of reimplementing.",
|
|
34
|
+
"Close with real PR, test, and merge-status evidence; do not use diaries or workflow text as substitutes."
|
|
35
35
|
],
|
|
36
36
|
"gotchas": [
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
37
|
+
"Do not ask Francisco for manual approval on every PR: learning #198 confirms full autonomy with transparency and periodic reports.",
|
|
38
|
+
"Do not duplicate the evolution sandbox elsewhere: accepted-change apply already reuses evolution_log + sandbox/snapshot/rollback.",
|
|
39
|
+
"The historical FP rate for this audit class is high; if there is no concrete evidence, the item is not touched."
|
|
40
40
|
],
|
|
41
41
|
"params_schema": {
|
|
42
42
|
"audit_file": {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Run NEXO Core Fix Cycle
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this skill when a small group of NEXO core fixes must be implemented and verified without improvising the plane or repeating the same discovery and test phase every time.
|
|
4
4
|
|
|
5
5
|
## Steps
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
8
|
-
3.
|
|
9
|
-
4.
|
|
10
|
-
5.
|
|
11
|
-
6.
|
|
6
|
+
1. First fix the plane: public `nexo` repo, installed `~/.nexo` runtime, and public claims/docs. Do not mix those three worlds.
|
|
7
|
+
2. Open `nexo_task_open(...)` and `nexo_workflow_open(...)` before touching code. If the fix is action-related, also pass through `nexo_cortex_decide(...)`.
|
|
8
|
+
3. Run the skill with `areas` adjusted to the fix. The helper returns the file map and runs the focused test battery for `protocol`, `plane`, `guard`, `cortex`, and/or `release`.
|
|
9
|
+
4. Implement the smallest defensible change only on the correct surface. If the problem is product-level, fix it in the repo, not in `~/.nexo`.
|
|
10
|
+
5. Rerun the skill to revalidate the exact test cluster touched by the fix.
|
|
11
|
+
6. Close with `nexo_task_close(...)` and real evidence. If there was a real edit, leave `change_log` and capture a learning if a canonical rule changed.
|
|
12
12
|
|
|
13
13
|
## Gotchas
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
14
|
+
- Do not use diary, workflow text, or intuition as a substitute for real git/tests/runtime evidence.
|
|
15
|
+
- If the fix touches doctor or public claims, set the explicit `plane` before running diagnostics.
|
|
16
|
+
- If the fix touches release or runtime update, use the official path (`nexo update`, doctor, final release skill), not side scripts.
|
|
17
|
+
- If the helper does not find an area, add the new surface explicitly to the skill instead of continuing scattered manual grep.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "SK-RUN-NEXO-CORE-FIX-CYCLE",
|
|
3
3
|
"name": "Run NEXO Core Fix Cycle",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Map impacted core surfaces and run focused verification for small NEXO fix cycles without mixing the public repo, runtime, and unverified claims.",
|
|
5
5
|
"level": "published",
|
|
6
6
|
"mode": "hybrid",
|
|
7
7
|
"source_kind": "core",
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"verification"
|
|
17
17
|
],
|
|
18
18
|
"trigger_patterns": [
|
|
19
|
-
"
|
|
19
|
+
"two nexo core fixes",
|
|
20
20
|
"core fix cycle",
|
|
21
|
-
"enforcement
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"protocol enforcement",
|
|
22
|
+
"plane before diagnosis",
|
|
23
|
+
"nexo core fix cycle"
|
|
24
24
|
],
|
|
25
25
|
"params_schema": {
|
|
26
26
|
"areas": {
|
|
@@ -4,8 +4,8 @@ Examples:
|
|
|
4
4
|
+ User: "Vamos a arreglar el bug del checkout" -> yes
|
|
5
5
|
+ User: "Hazme un refactor del login de CanaRirural" -> yes
|
|
6
6
|
+ User: "Revisa la PR del orchestrator" -> yes
|
|
7
|
-
- User: "
|
|
8
|
-
- User: "
|
|
7
|
+
- User: "what time is it" -> no
|
|
8
|
+
- User: "thanks, that's done" -> no
|
|
9
9
|
- User: "dime un chiste" -> no
|
|
10
10
|
|
|
11
11
|
Now decide. Input:
|