mcp-nervous-system 1.7.4 → 1.8.1
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 +21 -3
- package/README.md.bak.1772815524 +172 -0
- package/index.js +704 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
7 mechanically enforced rules that prevent the most common failure modes when LLMs have access to real infrastructure: context loss, silent failures, file damage, goal drift, and overreach.
|
|
6
6
|
|
|
7
|
-
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 19 tools including configuration drift detection and emergency kill switch. Battle-tested on
|
|
7
|
+
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 19 tools including configuration drift detection and emergency kill switch. Battle-tested on a 13-agent AI family running 29 processes 24/7 on a single VPS. 58+ violations logged, 0 bypassed.
|
|
8
8
|
|
|
9
9
|
## The Problem
|
|
10
10
|
|
|
@@ -60,7 +60,12 @@ Protocol: MCP 2024-11-05 (Streamable HTTP + SSE)
|
|
|
60
60
|
Authentication: None required
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
## NEW in v1.
|
|
63
|
+
## NEW in v1.8.0
|
|
64
|
+
|
|
65
|
+
**Tamara Reference Implementation + Case Study** (2 new resources)
|
|
66
|
+
Production reference implementation of an autonomous AI operations manager built on the Nervous System. Includes full architecture documentation, build-your-own guide, and case study with real metrics from managing 13 agents across 5 platforms.
|
|
67
|
+
|
|
68
|
+
## v1.7.4
|
|
64
69
|
|
|
65
70
|
**drift_audit** (free tier)
|
|
66
71
|
Configuration drift detection across 5 scopes: roles, versions, files, processes, and website. Scans source-of-truth files (family-roles.json, package.json, UNTOUCHABLE_FILES.txt) against all downstream references - HTML pages, JSON configs, markdown docs, and running PM2 processes. Change one file, drift_audit tells you everywhere else that needs updating. The closed loop that keeps your entire system consistent.
|
|
@@ -127,13 +132,26 @@ The Nervous System provides practical compliance tools for the EU AI Act. See th
|
|
|
127
132
|
|
|
128
133
|
https://api.100levelup.com/family/eu-ai-act.html
|
|
129
134
|
|
|
130
|
-
##
|
|
135
|
+
## Production Reference: Tamara
|
|
136
|
+
|
|
137
|
+
Tamara is an autonomous AI operations manager built on the Nervous System framework. She manages 13 AI agents across 5 platforms, serving 175 countries from a $24/month VPS - without dedicated DevOps staff.
|
|
138
|
+
|
|
139
|
+
Tamara is the proof that the Nervous System works in production. She runs 60-minute autonomous check cycles, detects configuration drift, dispatches remediation agents, and reports to the human operator only when judgment is needed.
|
|
140
|
+
|
|
141
|
+
- **Case Study**: Use the `nervous-system://case-study` resource for full production metrics
|
|
142
|
+
- **Reference Implementation**: Use the `nervous-system://tamara-reference` resource for architecture details and build-your-own guide
|
|
143
|
+
- **Enterprise Support**: For organizations deploying AI agent fleets at scale, implementation consulting is available at wa.me/18184399770
|
|
144
|
+
- **Blog**: [Meet Tamara](https://api.100levelup.com/family/blog/meet-tamara.md) | [Why AI Agent Management Is the Next Infrastructure Layer](https://api.100levelup.com/family/blog/ai-agent-management.md)
|
|
145
|
+
|
|
146
|
+
## Resources (7)
|
|
131
147
|
|
|
132
148
|
- `nervous-system://framework` - The complete framework
|
|
133
149
|
- `nervous-system://quick-start` - Quick start guide
|
|
134
150
|
- `nervous-system://rules` - The 7 core rules
|
|
135
151
|
- `nervous-system://templates` - Templates for handoffs, worklogs, preflight
|
|
136
152
|
- `nervous-system://drift-audit` - Configuration drift detection
|
|
153
|
+
- `nervous-system://tamara-reference` - Tamara autonomous ops manager reference implementation
|
|
154
|
+
- `nervous-system://case-study` - Palyan Family AI System production case study
|
|
137
155
|
|
|
138
156
|
## Production Stats
|
|
139
157
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# The Nervous System
|
|
2
|
+
|
|
3
|
+
**LLM Behavioral Enforcement Framework**
|
|
4
|
+
|
|
5
|
+
7 mechanically enforced rules that prevent the most common failure modes when LLMs have access to real infrastructure: context loss, silent failures, file damage, goal drift, and overreach.
|
|
6
|
+
|
|
7
|
+
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 19 tools including configuration drift detection and emergency kill switch. Battle-tested on an 11-member AI family running 30 processes 24/7 on a single VPS. 58+ violations logged, 0 bypassed.
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
When you give an LLM access to your file system, bash, and production infrastructure, it will eventually:
|
|
12
|
+
|
|
13
|
+
- Edit a file it shouldn't touch
|
|
14
|
+
- Lose context between sessions and start over
|
|
15
|
+
- Drift from the original objective during long tasks
|
|
16
|
+
- Fail silently when a session times out
|
|
17
|
+
- Make logic changes without asking
|
|
18
|
+
- Disappear into debug loops
|
|
19
|
+
|
|
20
|
+
The Nervous System solves all of these with rules enforced by external mechanisms the LLM cannot override.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### Claude Desktop
|
|
25
|
+
|
|
26
|
+
Add to your `claude_desktop_config.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"nervous-system": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "mcp-nervous-system"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Claude Code
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claude mcp add nervous-system npx mcp-nervous-system
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Direct
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx mcp-nervous-system
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Server starts on port 3475 with SSE, HTTP, and health endpoints.
|
|
52
|
+
|
|
53
|
+
### Hosted (No Install)
|
|
54
|
+
|
|
55
|
+
The server is live and ready to use:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
URL: https://api.100levelup.com/mcp-ns/
|
|
59
|
+
Protocol: MCP 2024-11-05 (Streamable HTTP + SSE)
|
|
60
|
+
Authentication: None required
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## NEW in v1.7.3
|
|
64
|
+
|
|
65
|
+
**drift_audit** (free tier)
|
|
66
|
+
Configuration drift detection across 5 scopes: roles, versions, files, processes, and website. Scans source-of-truth files (family-roles.json, package.json, UNTOUCHABLE_FILES.txt) against all downstream references - HTML pages, JSON configs, markdown docs, and running PM2 processes. Change one file, drift_audit tells you everywhere else that needs updating. The closed loop that keeps your entire system consistent.
|
|
67
|
+
|
|
68
|
+
**Positioning: Auto mode decides what Claude CAN do. The Nervous System governs HOW it behaves while doing it.**
|
|
69
|
+
|
|
70
|
+
## The 7 Rules
|
|
71
|
+
|
|
72
|
+
| # | Rule | What It Prevents |
|
|
73
|
+
|---|------|-----------------|
|
|
74
|
+
| 1 | **Dispatch Don't Do** | Debug loops, rabbit holes. Tasks > 2 messages get dispatched. |
|
|
75
|
+
| 2 | **Untouchable** | File damage. Protected files mechanically blocked from editing. |
|
|
76
|
+
| 3 | **Write Progress** | Silent failures. Progress noted before each action. |
|
|
77
|
+
| 4 | **Step Back Every 4** | Goal drift. Forced reflection every 4 messages. |
|
|
78
|
+
| 5 | **Delegate and Return** | Invisible work. Background tasks reported immediately. |
|
|
79
|
+
| 6 | **Ask Before Touching** | Unauthorized changes. Logic changes need human approval. |
|
|
80
|
+
| 7 | **Hand Off** | Context loss. Written handoffs every 3-4 exchanges. |
|
|
81
|
+
|
|
82
|
+
## MCP Tools (12)
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|------------|
|
|
86
|
+
| `get_framework` | Complete framework: all rules, permission protocol, enforcement patterns |
|
|
87
|
+
| `guardrail_rules` | The 7 core rules with triggers, enforcement, and failure modes |
|
|
88
|
+
| `preflight_check` | File protection system: shell script blocks edits to protected files |
|
|
89
|
+
| `session_handoff` | Context preservation: templates for handoff documents |
|
|
90
|
+
| `worklog` | Progress documentation pattern |
|
|
91
|
+
| `violation_logging` | Audit trail: timestamp, type, context for every violation |
|
|
92
|
+
| `step_back_check` | Forced reflection system |
|
|
93
|
+
| `get_nervous_system_info` | System overview and operational stats |
|
|
94
|
+
| `emergency_kill_switch` | Emergency shutdown of all PM2 processes. Requires kill switch secret. Logs to tamper-evident audit trail |
|
|
95
|
+
| `verify_audit_chain` | Walks the SHA-256 hash-chained audit log and verifies every entry. Returns chain integrity status |
|
|
96
|
+
| `dispatch_to_llm` | Spawns a background LLM agent to handle a task. Checks RAM, enforces max 2 concurrent dispatches |
|
|
97
|
+
| `drift_audit` | Configuration drift detection across roles, versions, files, processes, and website. Finds stale values everywhere. |
|
|
98
|
+
|
|
99
|
+
## Kill Switch
|
|
100
|
+
|
|
101
|
+
The `emergency_kill_switch` tool provides an emergency shutdown capability. Send a POST request to `/kill` with the kill switch secret to immediately stop all PM2 processes. Every activation is logged to the tamper-evident audit trail with SHA-256 hash chaining, so kill switch events cannot be hidden or altered after the fact.
|
|
102
|
+
|
|
103
|
+
- Requires authentication (kill switch secret)
|
|
104
|
+
- Logs to hash-chained audit trail
|
|
105
|
+
- Returns confirmation with affected process count
|
|
106
|
+
|
|
107
|
+
## Tamper-Evident Audit Trail
|
|
108
|
+
|
|
109
|
+
Every guardrail violation, kill switch activation, and dispatch event is recorded in a SHA-256 hash-chained audit log. Each entry includes the hash of the previous entry, making it cryptographically impossible to alter or delete past records without breaking the chain.
|
|
110
|
+
|
|
111
|
+
- Use `verify_audit_chain` to walk the entire chain and verify integrity
|
|
112
|
+
- Returns: valid/invalid status, entry count, and break point if tampered
|
|
113
|
+
- 58+ violations logged, 0 bypassed, 0 chain breaks
|
|
114
|
+
|
|
115
|
+
## Dispatch to LLM
|
|
116
|
+
|
|
117
|
+
The `dispatch_to_llm` tool enables a brain + agents architecture. Instead of one LLM session doing everything, complex tasks get dispatched to background agents that run independently under the same 7 rules.
|
|
118
|
+
|
|
119
|
+
- Checks available RAM (requires 500MB+)
|
|
120
|
+
- Enforces max 2 concurrent dispatches
|
|
121
|
+
- Returns PID and log file path for monitoring
|
|
122
|
+
- Every dispatched agent runs under the same nervous system guardrails
|
|
123
|
+
|
|
124
|
+
## EU AI Act Compliance
|
|
125
|
+
|
|
126
|
+
The Nervous System provides practical compliance tools for the EU AI Act. See the full compliance page at:
|
|
127
|
+
|
|
128
|
+
https://api.100levelup.com/family/eu-ai-act.html
|
|
129
|
+
|
|
130
|
+
## Resources (5)
|
|
131
|
+
|
|
132
|
+
- `nervous-system://framework` - The complete framework
|
|
133
|
+
- `nervous-system://quick-start` - Quick start guide
|
|
134
|
+
- `nervous-system://rules` - The 7 core rules
|
|
135
|
+
- `nervous-system://templates` - Templates for handoffs, worklogs, preflight
|
|
136
|
+
- `nervous-system://drift-audit` - Configuration drift detection
|
|
137
|
+
|
|
138
|
+
## Production Stats
|
|
139
|
+
|
|
140
|
+
From the live Palyan Family AI System deployment (Feb 28 - Mar 5, 2026):
|
|
141
|
+
|
|
142
|
+
- **58+** violations caught
|
|
143
|
+
- **29** edits blocked by preflight
|
|
144
|
+
- **13** unique files protected
|
|
145
|
+
- **0** rules bypassed
|
|
146
|
+
- **28** processes monitored
|
|
147
|
+
- **7** days continuous operation
|
|
148
|
+
|
|
149
|
+
## Live Demo
|
|
150
|
+
|
|
151
|
+
Try it yourself (no login required):
|
|
152
|
+
|
|
153
|
+
- **[Interactive Demo](https://api.100levelup.com/family/arthur.html?guest=1)** - Talk to a governed LLM and try to break the rules
|
|
154
|
+
- **[Audit Dashboard](https://api.100levelup.com/family/audit.html)** - See real violation history with timeline
|
|
155
|
+
- **[System Status](https://api.100levelup.com/family/status.html)** - Live health checks
|
|
156
|
+
- **[API Documentation](https://api.100levelup.com/family/api-docs.html)** - Full tool and resource reference
|
|
157
|
+
- **[Case Study](https://api.100levelup.com/family/case-study.html)** - Production deployment data
|
|
158
|
+
- **[Plain English Rules](https://api.100levelup.com/family/rules-plain.html)** - For non-technical stakeholders
|
|
159
|
+
- **[Incident Response](https://api.100levelup.com/family/incident-response.html)** - Detection, containment, resolution
|
|
160
|
+
- **[EU AI Act Compliance](https://api.100levelup.com/family/eu-ai-act.html)** - Practical EU AI Act compliance tools
|
|
161
|
+
|
|
162
|
+
## Philosophy
|
|
163
|
+
|
|
164
|
+
> "LLMs can't reliably self-enforce promises. Guardrails work via preflight.sh, violation logs, and catching drift. Build enforcement systems, don't make promises."
|
|
165
|
+
|
|
166
|
+
If a guardrail can be violated by the thing it guards, it is not a guardrail. It is a suggestion.
|
|
167
|
+
|
|
168
|
+
Every rule in the Nervous System is enforced by an external mechanism: a shell script, a timer, a separate monitoring process. The LLM cannot override, circumvent, or ignore them.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
package/index.js
CHANGED
|
@@ -192,7 +192,7 @@ const MCP_VERSION = '2024-11-05';
|
|
|
192
192
|
// Server info
|
|
193
193
|
const SERVER_INFO = {
|
|
194
194
|
name: 'nervous-system',
|
|
195
|
-
version: '1.
|
|
195
|
+
version: '1.8.0'
|
|
196
196
|
};
|
|
197
197
|
|
|
198
198
|
// ============================================================
|
|
@@ -201,7 +201,7 @@ const SERVER_INFO = {
|
|
|
201
201
|
|
|
202
202
|
const FRAMEWORK = {
|
|
203
203
|
name: 'The Nervous System',
|
|
204
|
-
version: '1.
|
|
204
|
+
version: '1.8.0',
|
|
205
205
|
author: 'Arthur Palyan',
|
|
206
206
|
tagline: 'Anthropic built the brain. Arthur built the nervous system that keeps it from hurting itself.',
|
|
207
207
|
problem: 'LLMs lose context between sessions, loop on problems instead of dispatching, silently fail without progress notes, edit protected files, drift from the real problem, and solve instead of asking.',
|
|
@@ -669,14 +669,14 @@ const TOOLS = [
|
|
|
669
669
|
{
|
|
670
670
|
name: 'drift_audit',
|
|
671
671
|
annotations: { title: 'Configuration Drift Audit', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
672
|
-
description: 'Scans for configuration drift - finds files, docs, and configs that reference outdated values. Detects when a file is renamed but references are not updated, when roles change but downstream docs still show old values,
|
|
672
|
+
description: 'Scans for configuration drift - finds files, docs, and configs that reference outdated values. Detects when a file is renamed but references are not updated, when roles change but downstream docs still show old values, when running processes do not match documentation, or when bots fail compliance with the 6 universal standards. Scopes: roles, versions, files, processes, website, platforms, docs, bots.',
|
|
673
673
|
inputSchema: {
|
|
674
674
|
type: 'object',
|
|
675
675
|
properties: {
|
|
676
676
|
scope: {
|
|
677
677
|
type: 'string',
|
|
678
|
-
enum: ['full', 'roles', 'versions', 'files', 'processes', 'website'],
|
|
679
|
-
description: 'What to audit. full=everything, roles=family role consistency, versions=NS version numbers, files=file reference integrity, processes=PM2 vs docs, website=HTML pages and configs for stale values'
|
|
678
|
+
enum: ['full', 'roles', 'versions', 'files', 'processes', 'website', 'docs'],
|
|
679
|
+
description: 'What to audit. full=everything, roles=family role consistency, versions=NS version numbers, files=file reference integrity, processes=PM2 vs docs, website=HTML pages and configs for stale values, docs=compares reality (pm2, ports, crons, dept folders) against BUSINESS_BUILDER.md, LLM_STARTUP.md, family-roles.json'
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
682
|
}
|
|
@@ -751,6 +751,18 @@ const TOOLS = [
|
|
|
751
751
|
type: 'object',
|
|
752
752
|
properties: {}
|
|
753
753
|
}
|
|
754
|
+
},
|
|
755
|
+
// NEW: Bot Compliance Check
|
|
756
|
+
{
|
|
757
|
+
name: 'bot_compliance_check',
|
|
758
|
+
annotations: { title: 'Bot Compliance Check', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
759
|
+
description: 'Checks all public bot files against the 6 mandatory universal standards: (1) thinking message with 3-sec delay, (2) persistent typing indicator, (3) owner self-identification, (4) acceptance philosophy in prompt, (5) read receipts, (6) session summary extraction. Returns pass/fail per bot per standard.',
|
|
760
|
+
inputSchema: {
|
|
761
|
+
type: 'object',
|
|
762
|
+
properties: {
|
|
763
|
+
bot: { type: 'string', description: 'Check a specific bot file path, or omit to check all 10 public bots' }
|
|
764
|
+
}
|
|
765
|
+
}
|
|
754
766
|
}
|
|
755
767
|
];
|
|
756
768
|
|
|
@@ -761,6 +773,8 @@ const RESOURCES = [
|
|
|
761
773
|
{ uri: 'nervous-system://rules', name: 'The 7 Core Rules', description: 'All 7 behavioral rules with explanations and enforcement', mimeType: 'text/plain' },
|
|
762
774
|
{ uri: 'nervous-system://templates', name: 'Templates', description: 'Ready-to-use templates for handoffs, worklogs, preflight, and untouchable lists', mimeType: 'text/plain' },
|
|
763
775
|
{ uri: 'nervous-system://drift-audit', name: 'Drift Audit', description: 'Configuration drift detection - checks roles, versions, file references, and running processes against source-of-truth files', mimeType: 'text/plain' },
|
|
776
|
+
{ uri: 'nervous-system://tamara-reference', name: 'Tamara Reference Implementation', description: 'Autonomous AI operations manager - reference implementation for managing AI agent fleets using the Nervous System framework', mimeType: 'text/plain' },
|
|
777
|
+
{ uri: 'nervous-system://case-study', name: 'Palyan Family AI System Case Study', description: 'Production case study: 13 agents, 5 platforms, 175 countries, $24/month - autonomous AI operations at scale', mimeType: 'text/plain' },
|
|
764
778
|
];
|
|
765
779
|
|
|
766
780
|
// ============================================================
|
|
@@ -1307,11 +1321,386 @@ function auditWebsite() {
|
|
|
1307
1321
|
return { drifts, cleanChecks };
|
|
1308
1322
|
}
|
|
1309
1323
|
|
|
1324
|
+
function auditPlatforms() {
|
|
1325
|
+
const drifts = [];
|
|
1326
|
+
let cleanChecks = 0;
|
|
1327
|
+
|
|
1328
|
+
let registry;
|
|
1329
|
+
try {
|
|
1330
|
+
registry = JSON.parse(fs.readFileSync('/root/family-data/platform-features.json', 'utf8'));
|
|
1331
|
+
} catch (e) {
|
|
1332
|
+
return { drifts: [{ type: 'platform_registry_missing', source: '/root/family-data/platform-features.json', target: '', field: 'exists', expected: 'true', found: 'false' }], cleanChecks: 0 };
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
const featurePatterns = {
|
|
1336
|
+
property_lookup: /require\(.*harout-property-lookup.*\)|propertyLookup/,
|
|
1337
|
+
calendly_booking: /calendly|book_calendly/i,
|
|
1338
|
+
write_log: /write_log/,
|
|
1339
|
+
doc_generation: /generateNDA|generateDoc|doc-generator/,
|
|
1340
|
+
nda_generation: /generateNDA|generateDoc|doc-generator/,
|
|
1341
|
+
doc_generation_via_link: /api\.100levelup\.com\/family\/docs|doc-generator/,
|
|
1342
|
+
ip_agreement: /ip.?agreement|generateIP/i,
|
|
1343
|
+
pdf_sending: /sendDocument|send.*pdf/i,
|
|
1344
|
+
admin_commands: /admin|\/start|isAdmin/i,
|
|
1345
|
+
tool_execution: /tool|function_call|executeTool/i,
|
|
1346
|
+
search_resource: /search_resource|searchResource/i,
|
|
1347
|
+
coaching: /coach|system.*prompt|openai|anthropic/i,
|
|
1348
|
+
legal_qa: /legal|lawyer|counsel|system.*prompt|openai|anthropic/i,
|
|
1349
|
+
real_estate_qa: /real.?estate|property|system.*prompt|openai|anthropic/i,
|
|
1350
|
+
translation: /translat/i,
|
|
1351
|
+
multilingual_support: /translat|language/i,
|
|
1352
|
+
fitness_training: /fitness|training|workout|system.*prompt|openai|anthropic/i,
|
|
1353
|
+
program_design: /program|routine|plan/i,
|
|
1354
|
+
client_notes: /notes|client.*note/i,
|
|
1355
|
+
accounting: /account|tax|bookkeep|system.*prompt|openai|anthropic/i,
|
|
1356
|
+
tax_prep: /tax/i,
|
|
1357
|
+
bookkeeping: /bookkeep|ledger|account/i,
|
|
1358
|
+
file_processing: /file|upload|attachment/i,
|
|
1359
|
+
csv_processing: /csv|comma.?separated/i,
|
|
1360
|
+
pdf_processing: /pdf|document.*process/i,
|
|
1361
|
+
youth_empowerment: /youth|empower|system.*prompt|openai|anthropic/i,
|
|
1362
|
+
training_sales: /training|sales|program/i,
|
|
1363
|
+
calendar_management: /calendar|schedule|booking/i,
|
|
1364
|
+
gang_consulting: /gang|consult|intervention/i,
|
|
1365
|
+
listing_management: /listing|mls|manage/i,
|
|
1366
|
+
lead_tracking: /lead|track|crm/i,
|
|
1367
|
+
nod_nts: /nod|nts|notice.*default/i,
|
|
1368
|
+
fix_flip: /fix.*flip|flip.*fix|rehab/i
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1371
|
+
for (const [memberName, member] of Object.entries(registry.members)) {
|
|
1372
|
+
for (const [platformName, platform] of Object.entries(member.platforms)) {
|
|
1373
|
+
const botFile = platform.file;
|
|
1374
|
+
|
|
1375
|
+
if (!fs.existsSync(botFile)) {
|
|
1376
|
+
drifts.push({
|
|
1377
|
+
type: 'platform_file_missing',
|
|
1378
|
+
source: memberName + '/' + platformName,
|
|
1379
|
+
target: botFile,
|
|
1380
|
+
field: 'exists',
|
|
1381
|
+
expected: 'true',
|
|
1382
|
+
found: 'false'
|
|
1383
|
+
});
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
let fileContent;
|
|
1388
|
+
try {
|
|
1389
|
+
fileContent = fs.readFileSync(botFile, 'utf8');
|
|
1390
|
+
} catch (e) {
|
|
1391
|
+
drifts.push({
|
|
1392
|
+
type: 'platform_file_unreadable',
|
|
1393
|
+
source: memberName + '/' + platformName,
|
|
1394
|
+
target: botFile,
|
|
1395
|
+
field: 'readable',
|
|
1396
|
+
expected: 'true',
|
|
1397
|
+
found: 'false'
|
|
1398
|
+
});
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
for (const feature of platform.features) {
|
|
1403
|
+
const pattern = featurePatterns[feature];
|
|
1404
|
+
if (pattern) {
|
|
1405
|
+
if (pattern.test(fileContent)) {
|
|
1406
|
+
cleanChecks++;
|
|
1407
|
+
} else {
|
|
1408
|
+
drifts.push({
|
|
1409
|
+
type: 'platform_feature_missing',
|
|
1410
|
+
source: memberName + '/' + platformName,
|
|
1411
|
+
target: botFile,
|
|
1412
|
+
field: feature,
|
|
1413
|
+
expected: 'present_in_code',
|
|
1414
|
+
found: 'not_found'
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
} else {
|
|
1418
|
+
// Fallback: check for the feature name as a string
|
|
1419
|
+
if (fileContent.includes(feature)) {
|
|
1420
|
+
cleanChecks++;
|
|
1421
|
+
} else {
|
|
1422
|
+
drifts.push({
|
|
1423
|
+
type: 'platform_feature_missing',
|
|
1424
|
+
source: memberName + '/' + platformName,
|
|
1425
|
+
target: botFile,
|
|
1426
|
+
field: feature,
|
|
1427
|
+
expected: 'present_in_code',
|
|
1428
|
+
found: 'not_found'
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
return { drifts, cleanChecks };
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// ============================================================
|
|
1440
|
+
// DOC DRIFT AUDIT - Compares REALITY against DOCS
|
|
1441
|
+
// ============================================================
|
|
1442
|
+
|
|
1443
|
+
function auditBotCompliance() {
|
|
1444
|
+
const drifts = [];
|
|
1445
|
+
let cleanChecks = 0;
|
|
1446
|
+
const compliance = runBotComplianceCheck();
|
|
1447
|
+
for (const r of compliance.results) {
|
|
1448
|
+
for (const [standard, check] of Object.entries(r.standards)) {
|
|
1449
|
+
if (check.pass) {
|
|
1450
|
+
cleanChecks++;
|
|
1451
|
+
} else {
|
|
1452
|
+
drifts.push({
|
|
1453
|
+
type: 'bot_compliance',
|
|
1454
|
+
source: r.file,
|
|
1455
|
+
target: 'BOT_BUILD_TEMPLATE.md',
|
|
1456
|
+
field: standard,
|
|
1457
|
+
expected: 'implemented',
|
|
1458
|
+
found: check.detail
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return { drifts, cleanChecks };
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
function auditDocs() {
|
|
1467
|
+
const drifts = [];
|
|
1468
|
+
let cleanChecks = 0;
|
|
1469
|
+
|
|
1470
|
+
// 1A. Process drift: pm2 vs docs
|
|
1471
|
+
let pm2Procs = [];
|
|
1472
|
+
try {
|
|
1473
|
+
pm2Procs = JSON.parse(execSync('pm2 jlist', { timeout: 10000 }).toString());
|
|
1474
|
+
} catch (e) {
|
|
1475
|
+
drifts.push({ type: 'doc_pm2_error', source: 'pm2', target: 'docs', field: 'pm2_access', expected: 'readable', found: e.message });
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
const pm2Names = {};
|
|
1479
|
+
for (const p of pm2Procs) {
|
|
1480
|
+
pm2Names[p.name] = p.pm2_env ? p.pm2_env.status : 'unknown';
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// Extract process tables from BUSINESS_BUILDER.md and LLM_STARTUP.md
|
|
1484
|
+
const bbPath = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'BUSINESS_BUILDER.md') : null;
|
|
1485
|
+
const startupPath = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'LLM_STARTUP.md') : null;
|
|
1486
|
+
const rolesPath = projectPath('roles_file');
|
|
1487
|
+
|
|
1488
|
+
const bbContent = bbPath ? safeReadFile(bbPath) : null;
|
|
1489
|
+
const startupContent = startupPath ? safeReadFile(startupPath) : null;
|
|
1490
|
+
|
|
1491
|
+
function extractProcessNames(mdContent, docName) {
|
|
1492
|
+
const names = {};
|
|
1493
|
+
if (!mdContent) return names;
|
|
1494
|
+
// Match table rows like: | name | file | purpose |
|
|
1495
|
+
const lines = mdContent.split('\n');
|
|
1496
|
+
let inProcessTable = false;
|
|
1497
|
+
for (const line of lines) {
|
|
1498
|
+
if (line.match(/\|\s*Name\s*\|\s*File\s*\|\s*Purpose/i) || line.match(/PM2 PROCESSES/i)) {
|
|
1499
|
+
inProcessTable = true;
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
if (inProcessTable && line.match(/^\|[-\s|]+\|$/)) continue; // separator row
|
|
1503
|
+
if (inProcessTable && line.startsWith('|')) {
|
|
1504
|
+
const cells = line.split('|').map(c => c.trim()).filter(c => c);
|
|
1505
|
+
if (cells.length >= 2) {
|
|
1506
|
+
const name = cells[0];
|
|
1507
|
+
if (name && !name.match(/^(Name|---|Port|Schedule)/i)) {
|
|
1508
|
+
names[name] = docName;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
} else if (inProcessTable && !line.startsWith('|') && line.trim()) {
|
|
1512
|
+
inProcessTable = false;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
return names;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
const bbProcs = extractProcessNames(bbContent, 'BUSINESS_BUILDER.md');
|
|
1519
|
+
const startupProcs = extractProcessNames(startupContent, 'LLM_STARTUP.md');
|
|
1520
|
+
|
|
1521
|
+
// Merge doc process names
|
|
1522
|
+
const allDocProcs = { ...bbProcs, ...startupProcs };
|
|
1523
|
+
|
|
1524
|
+
// Flag: processes in pm2 but not in any doc
|
|
1525
|
+
for (const name of Object.keys(pm2Names)) {
|
|
1526
|
+
if (allDocProcs[name]) {
|
|
1527
|
+
cleanChecks++;
|
|
1528
|
+
} else {
|
|
1529
|
+
drifts.push({ type: 'doc_process_undocumented', source: 'pm2', target: 'docs', field: name, expected: 'documented', found: 'not in any doc process table' });
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// Flag: processes in docs but not in pm2
|
|
1534
|
+
for (const [name, doc] of Object.entries(allDocProcs)) {
|
|
1535
|
+
if (pm2Names[name] !== undefined) {
|
|
1536
|
+
cleanChecks++;
|
|
1537
|
+
} else {
|
|
1538
|
+
drifts.push({ type: 'doc_process_missing_from_pm2', source: doc, target: 'pm2', field: name, expected: 'in pm2', found: 'not found' });
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// 1B. Family member drift: dept folders vs family-roles.json
|
|
1543
|
+
const roles = rolesPath ? safeReadJSON(rolesPath) : null;
|
|
1544
|
+
if (roles && roles.members) {
|
|
1545
|
+
const roleIds = new Set(roles.members.map(m => m.id).filter(Boolean));
|
|
1546
|
+
const roleNames = new Set(roles.members.map(m => (m.name || '').toLowerCase()));
|
|
1547
|
+
|
|
1548
|
+
// Scan /root/dept-* directories
|
|
1549
|
+
const projRoot = projectPath('project_root') || '/root';
|
|
1550
|
+
try {
|
|
1551
|
+
const deptDirs = fs.readdirSync(projRoot).filter(d => d.startsWith('dept-') && fs.statSync(path.join(projRoot, d)).isDirectory());
|
|
1552
|
+
for (const dir of deptDirs) {
|
|
1553
|
+
const deptName = dir.replace('dept-', '');
|
|
1554
|
+
// Check if this dept name matches any member id or name
|
|
1555
|
+
const hasMatch = roleIds.has(deptName) ||
|
|
1556
|
+
roleNames.has(deptName) ||
|
|
1557
|
+
(deptName === 'uncle-lou' && (roleIds.has('lou') || roleNames.has('uncle lou')));
|
|
1558
|
+
if (hasMatch) {
|
|
1559
|
+
cleanChecks++;
|
|
1560
|
+
} else {
|
|
1561
|
+
drifts.push({ type: 'doc_dept_no_member', source: dir, target: 'family-roles.json', field: deptName, expected: 'member entry', found: 'no matching member' });
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
} catch (e) {}
|
|
1565
|
+
|
|
1566
|
+
// Check members have matching dept or process
|
|
1567
|
+
for (const m of roles.members) {
|
|
1568
|
+
const memberId = m.id || (m.name || '').toLowerCase();
|
|
1569
|
+
const deptPath = path.join(projRoot, 'dept-' + memberId);
|
|
1570
|
+
const altDeptPath = memberId === 'lou' ? path.join(projRoot, 'dept-uncle-lou') : null;
|
|
1571
|
+
const hasProcs = m.procs && m.procs.length > 0;
|
|
1572
|
+
const hasDept = fs.existsSync(deptPath) || (altDeptPath && fs.existsSync(altDeptPath));
|
|
1573
|
+
const hasPm2 = m.pm2_process ? pm2Names[m.pm2_process] !== undefined : false;
|
|
1574
|
+
|
|
1575
|
+
if (hasDept || hasProcs || hasPm2) {
|
|
1576
|
+
cleanChecks++;
|
|
1577
|
+
} else {
|
|
1578
|
+
drifts.push({ type: 'doc_member_no_presence', source: 'family-roles.json', target: 'system', field: memberId, expected: 'dept folder or pm2 process', found: 'neither found' });
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// Check member_count accuracy
|
|
1583
|
+
if (roles.stats && roles.stats.member_count !== roles.members.length) {
|
|
1584
|
+
drifts.push({ type: 'doc_stats_mismatch', source: 'family-roles.json', target: 'stats.member_count', field: 'member_count', expected: String(roles.members.length), found: String(roles.stats.member_count) });
|
|
1585
|
+
} else if (roles.stats) {
|
|
1586
|
+
cleanChecks++;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
// 1C. Port drift: ss vs docs
|
|
1591
|
+
let listeningPorts = [];
|
|
1592
|
+
try {
|
|
1593
|
+
const ssOutput = execSync('ss -tlnp 2>/dev/null', { timeout: 5000 }).toString();
|
|
1594
|
+
const portMatches = ssOutput.matchAll(/:(\d+)\s/g);
|
|
1595
|
+
const portSet = new Set();
|
|
1596
|
+
for (const m of portMatches) {
|
|
1597
|
+
const port = parseInt(m[1]);
|
|
1598
|
+
if (port >= 3000 && port < 4000) portSet.add(port);
|
|
1599
|
+
}
|
|
1600
|
+
listeningPorts = Array.from(portSet);
|
|
1601
|
+
} catch (e) {}
|
|
1602
|
+
|
|
1603
|
+
if (bbContent && listeningPorts.length > 0) {
|
|
1604
|
+
// Extract documented ports from BUSINESS_BUILDER.md
|
|
1605
|
+
const docPorts = new Set();
|
|
1606
|
+
const portMatches = bbContent.matchAll(/:(\d{4})\b/g);
|
|
1607
|
+
for (const m of portMatches) {
|
|
1608
|
+
const port = parseInt(m[1]);
|
|
1609
|
+
if (port >= 3000 && port < 4000) docPorts.add(port);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
for (const port of listeningPorts) {
|
|
1613
|
+
if (docPorts.has(port)) {
|
|
1614
|
+
cleanChecks++;
|
|
1615
|
+
} else {
|
|
1616
|
+
drifts.push({ type: 'doc_port_undocumented', source: 'ss -tlnp', target: 'BUSINESS_BUILDER.md', field: ':' + port, expected: 'documented', found: 'listening but not in docs' });
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
for (const port of docPorts) {
|
|
1621
|
+
if (listeningPorts.includes(port)) {
|
|
1622
|
+
cleanChecks++;
|
|
1623
|
+
} else {
|
|
1624
|
+
drifts.push({ type: 'doc_port_not_listening', source: 'BUSINESS_BUILDER.md', target: 'ss -tlnp', field: ':' + port, expected: 'listening', found: 'not active' });
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// 1D. Doc freshness
|
|
1630
|
+
const docsToCheck = [
|
|
1631
|
+
bbPath,
|
|
1632
|
+
startupPath,
|
|
1633
|
+
rolesPath,
|
|
1634
|
+
projectPath('data_dir') ? path.join(projectPath('data_dir'), 'SESSION_HANDOFF.md') : null
|
|
1635
|
+
].filter(Boolean);
|
|
1636
|
+
|
|
1637
|
+
const now = Date.now();
|
|
1638
|
+
const THREE_DAYS = 3 * 24 * 60 * 60 * 1000;
|
|
1639
|
+
const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
|
|
1640
|
+
|
|
1641
|
+
for (const docPath of docsToCheck) {
|
|
1642
|
+
try {
|
|
1643
|
+
const stat = fs.statSync(docPath);
|
|
1644
|
+
const age = now - stat.mtimeMs;
|
|
1645
|
+
const ageDays = Math.floor(age / (24 * 60 * 60 * 1000));
|
|
1646
|
+
const docName = path.basename(docPath);
|
|
1647
|
+
if (age > SEVEN_DAYS) {
|
|
1648
|
+
drifts.push({ type: 'doc_stale', source: docName, target: '', field: 'last_modified', expected: 'within 7 days', found: ageDays + ' days ago' });
|
|
1649
|
+
} else if (age > THREE_DAYS) {
|
|
1650
|
+
drifts.push({ type: 'doc_aging', source: docName, target: '', field: 'last_modified', expected: 'within 3 days', found: ageDays + ' days ago' });
|
|
1651
|
+
} else {
|
|
1652
|
+
cleanChecks++;
|
|
1653
|
+
}
|
|
1654
|
+
} catch (e) {
|
|
1655
|
+
drifts.push({ type: 'doc_missing', source: path.basename(docPath), target: '', field: 'exists', expected: 'true', found: 'false' });
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// 1E. Cron drift
|
|
1660
|
+
try {
|
|
1661
|
+
const crontab = execSync('crontab -l 2>/dev/null', { timeout: 5000 }).toString();
|
|
1662
|
+
const lines = crontab.split('\n');
|
|
1663
|
+
const activeCrons = lines.filter(l => l.trim() && !l.startsWith('#'));
|
|
1664
|
+
const commentedCrons = lines.filter(l => l.startsWith('# STOPPED') || (l.startsWith('#') && l.includes('.js') && !l.startsWith('# =') && !l.startsWith('# Only') && !l.startsWith('# All') && !l.startsWith('# PALYAN')));
|
|
1665
|
+
|
|
1666
|
+
// Check if BUSINESS_BUILDER mentions crons that are now stopped
|
|
1667
|
+
if (bbContent) {
|
|
1668
|
+
// Look for worker references in the doc that mention "Cron" schedules
|
|
1669
|
+
const cronRefs = bbContent.matchAll(/\|\s*([^\|]+\.(?:js|py))\s*\|[^\|]*\|\s*(?:Cron[^\|]*)\|/gi);
|
|
1670
|
+
for (const m of cronRefs) {
|
|
1671
|
+
const workerFile = m[1].trim();
|
|
1672
|
+
const basename = workerFile.split('/').pop();
|
|
1673
|
+
// Check if this cron is commented out
|
|
1674
|
+
const isStopped = commentedCrons.some(c => c.includes(basename));
|
|
1675
|
+
if (isStopped) {
|
|
1676
|
+
drifts.push({ type: 'doc_cron_stopped', source: 'BUSINESS_BUILDER.md', target: 'crontab', field: basename, expected: 'active (per doc)', found: 'STOPPED in crontab' });
|
|
1677
|
+
} else {
|
|
1678
|
+
cleanChecks++;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
// Check for active crons not mentioned in docs
|
|
1684
|
+
for (const cron of activeCrons) {
|
|
1685
|
+
const scriptMatch = cron.match(/([^\s/]+\.(?:js|py))/);
|
|
1686
|
+
if (!scriptMatch) continue;
|
|
1687
|
+
const scriptName = scriptMatch[1];
|
|
1688
|
+
if (bbContent && bbContent.includes(scriptName)) {
|
|
1689
|
+
cleanChecks++;
|
|
1690
|
+
} else {
|
|
1691
|
+
drifts.push({ type: 'doc_cron_undocumented', source: 'crontab', target: 'BUSINESS_BUILDER.md', field: scriptName, expected: 'documented', found: 'active cron not in docs' });
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
} catch (e) {}
|
|
1695
|
+
|
|
1696
|
+
return { drifts, cleanChecks };
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1310
1699
|
function runDriftAudit(scope) {
|
|
1311
1700
|
const timestamp = new Date().toISOString();
|
|
1312
1701
|
const allDrifts = [];
|
|
1313
1702
|
let totalClean = 0;
|
|
1314
|
-
const scopes = scope === 'full' ? ['roles', 'versions', 'files', 'processes', 'website'] : [scope];
|
|
1703
|
+
const scopes = scope === 'full' ? ['roles', 'versions', 'files', 'processes', 'website', 'platforms', 'docs', 'bots'] : [scope];
|
|
1315
1704
|
|
|
1316
1705
|
for (const s of scopes) {
|
|
1317
1706
|
let result;
|
|
@@ -1321,6 +1710,9 @@ function runDriftAudit(scope) {
|
|
|
1321
1710
|
case 'files': result = auditFiles(); break;
|
|
1322
1711
|
case 'processes': result = auditProcesses(); break;
|
|
1323
1712
|
case 'website': result = auditWebsite(); break;
|
|
1713
|
+
case 'platforms': result = auditPlatforms(); break;
|
|
1714
|
+
case 'docs': result = auditDocs(); break;
|
|
1715
|
+
case 'bots': result = auditBotCompliance(); break;
|
|
1324
1716
|
default: result = { drifts: [{ type: 'unknown_scope', source: '', target: '', field: s, expected: 'valid scope', found: 'unknown' }], cleanChecks: 0 };
|
|
1325
1717
|
}
|
|
1326
1718
|
allDrifts.push(...result.drifts);
|
|
@@ -1921,12 +2313,83 @@ function handleToolCall(name, args) {
|
|
|
1921
2313
|
case 'session_close': {
|
|
1922
2314
|
const driftResult = runDriftAudit('full');
|
|
1923
2315
|
const propagateResult = runAutoPropagators();
|
|
1924
|
-
|
|
2316
|
+
|
|
2317
|
+
// Platform parity warnings
|
|
2318
|
+
let platformWarnings = [];
|
|
2319
|
+
try {
|
|
2320
|
+
const platformRegistry = JSON.parse(fs.readFileSync('/root/family-data/platform-features.json', 'utf8'));
|
|
2321
|
+
for (const [memberName, member] of Object.entries(platformRegistry.members)) {
|
|
2322
|
+
const platformKeys = Object.keys(member.platforms);
|
|
2323
|
+
if (platformKeys.length < 2) continue;
|
|
2324
|
+
// Collect all features across platforms for this member
|
|
2325
|
+
const allFeatures = new Set();
|
|
2326
|
+
for (const pKey of platformKeys) {
|
|
2327
|
+
for (const f of member.platforms[pKey].features) {
|
|
2328
|
+
allFeatures.add(f);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
// Check each platform for missing features
|
|
2332
|
+
for (const pKey of platformKeys) {
|
|
2333
|
+
const platformFeatures = new Set(member.platforms[pKey].features);
|
|
2334
|
+
const missing = [];
|
|
2335
|
+
for (const f of allFeatures) {
|
|
2336
|
+
if (!platformFeatures.has(f)) {
|
|
2337
|
+
missing.push(f);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
if (missing.length > 0) {
|
|
2341
|
+
platformWarnings.push({
|
|
2342
|
+
member: memberName,
|
|
2343
|
+
platform: pKey,
|
|
2344
|
+
missing_features: missing,
|
|
2345
|
+
note: 'Features available on other platforms but not this one'
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
} catch (e) {
|
|
2351
|
+
// platform-features.json not available, skip warnings
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
// Check for platform-specific drifts
|
|
2355
|
+
const platformDrifts = driftResult.drifts.filter(function(d) { return d.type && d.type.startsWith('platform_'); });
|
|
2356
|
+
|
|
2357
|
+
// Extract doc-specific drifts for blockers
|
|
2358
|
+
const docDrifts = driftResult.drifts.filter(function(d) { return d.type && d.type.startsWith('doc_'); });
|
|
2359
|
+
const docDriftWarnings = [];
|
|
2360
|
+
if (docDrifts.length > 0) {
|
|
2361
|
+
const stale = docDrifts.filter(function(d) { return d.type === 'doc_stale' || d.type === 'doc_aging'; });
|
|
2362
|
+
const undocumented = docDrifts.filter(function(d) { return d.type === 'doc_process_undocumented'; });
|
|
2363
|
+
const missingFromPm2 = docDrifts.filter(function(d) { return d.type === 'doc_process_missing_from_pm2'; });
|
|
2364
|
+
const missingMembers = docDrifts.filter(function(d) { return d.type === 'doc_dept_no_member'; });
|
|
2365
|
+
const stoppedCrons = docDrifts.filter(function(d) { return d.type === 'doc_cron_stopped'; });
|
|
2366
|
+
if (stale.length > 0) docDriftWarnings.push('Stale docs: ' + stale.map(function(d) { return d.source + ' (' + d.found + ')'; }).join(', '));
|
|
2367
|
+
if (undocumented.length > 0) docDriftWarnings.push('Undocumented processes: ' + undocumented.map(function(d) { return d.field; }).join(', '));
|
|
2368
|
+
if (missingFromPm2.length > 0) docDriftWarnings.push('Docs reference missing processes: ' + missingFromPm2.map(function(d) { return d.field; }).join(', '));
|
|
2369
|
+
if (missingMembers.length > 0) docDriftWarnings.push('Dept folders without family-roles.json entry: ' + missingMembers.map(function(d) { return d.field; }).join(', '));
|
|
2370
|
+
if (stoppedCrons.length > 0) docDriftWarnings.push('Docs describe active crons that are STOPPED: ' + stoppedCrons.map(function(d) { return d.field; }).join(', '));
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
const result = {
|
|
1925
2374
|
timestamp: new Date().toISOString(),
|
|
1926
2375
|
drift_audit: driftResult,
|
|
1927
2376
|
propagation: propagateResult,
|
|
1928
2377
|
summary: driftResult.drift_count === 0 ? 'Session clean - no drifts, propagators run' : `${driftResult.drift_count} drifts found - review before closing`
|
|
1929
2378
|
};
|
|
2379
|
+
|
|
2380
|
+
if (docDriftWarnings.length > 0) {
|
|
2381
|
+
result.doc_drift_warnings = docDriftWarnings;
|
|
2382
|
+
result.doc_drift_blocker = 'DOCS STALE - update before closing session';
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
if (platformWarnings.length > 0) {
|
|
2386
|
+
result.platform_warnings = platformWarnings;
|
|
2387
|
+
}
|
|
2388
|
+
if (platformDrifts.length > 0) {
|
|
2389
|
+
result.platform_drift_count = platformDrifts.length;
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
return result;
|
|
1930
2393
|
}
|
|
1931
2394
|
|
|
1932
2395
|
case 'page_health': {
|
|
@@ -1945,6 +2408,10 @@ function handleToolCall(name, args) {
|
|
|
1945
2408
|
return runMCPAnalyzer(args.mode, args.output_path);
|
|
1946
2409
|
}
|
|
1947
2410
|
|
|
2411
|
+
case 'bot_compliance_check': {
|
|
2412
|
+
return runBotComplianceCheck(args.bot);
|
|
2413
|
+
}
|
|
2414
|
+
|
|
1948
2415
|
default:
|
|
1949
2416
|
return { error: 'Unknown tool' };
|
|
1950
2417
|
}
|
|
@@ -2073,6 +2540,108 @@ function runSelfCheck() {
|
|
|
2073
2540
|
};
|
|
2074
2541
|
}
|
|
2075
2542
|
|
|
2543
|
+
// BOT COMPLIANCE CHECK - Verifies 6 mandatory universal standards
|
|
2544
|
+
// ============================================================
|
|
2545
|
+
|
|
2546
|
+
function runBotComplianceCheck(botPath) {
|
|
2547
|
+
const BOT_FILES = [
|
|
2548
|
+
'/root/family-workers/lily-telegram-enhanced.js',
|
|
2549
|
+
'/root/dept-aram/aram-telegram.js',
|
|
2550
|
+
'/root/dept-harout/harout-telegram.js',
|
|
2551
|
+
'/root/dept-corona/corona-telegram.js',
|
|
2552
|
+
'/root/dept-soriano/soriano-telegram.js',
|
|
2553
|
+
'/root/family-workers/lily-instagram.js',
|
|
2554
|
+
'/root/family-workers/aram-instagram.js',
|
|
2555
|
+
'/root/family-workers/harout-instagram.js',
|
|
2556
|
+
'/root/family-workers/lily-facebook.js'
|
|
2557
|
+
];
|
|
2558
|
+
|
|
2559
|
+
const filesToCheck = botPath ? [botPath] : BOT_FILES;
|
|
2560
|
+
const results = [];
|
|
2561
|
+
let totalPass = 0;
|
|
2562
|
+
let totalFail = 0;
|
|
2563
|
+
|
|
2564
|
+
for (const filepath of filesToCheck) {
|
|
2565
|
+
let code = '';
|
|
2566
|
+
try {
|
|
2567
|
+
code = fs.readFileSync(filepath, 'utf8');
|
|
2568
|
+
} catch (e) {
|
|
2569
|
+
results.push({ file: filepath, error: 'File not found: ' + e.message, standards: {} });
|
|
2570
|
+
continue;
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
const isInstagram = filepath.includes('instagram');
|
|
2574
|
+
const isFacebook = filepath.includes('facebook');
|
|
2575
|
+
const isTelegram = !isInstagram && !isFacebook;
|
|
2576
|
+
const checks = {};
|
|
2577
|
+
|
|
2578
|
+
// Standard 1: Thinking message with 3-sec delay (setTimeout 3000)
|
|
2579
|
+
const hasThinkingDelay = code.includes('setTimeout') && (code.includes('3000') || code.includes('_thinkTimer') || code.includes('_thinkPhrases'));
|
|
2580
|
+
checks['1_thinking_message'] = { pass: hasThinkingDelay, detail: hasThinkingDelay ? 'Found setTimeout with thinking phrases' : 'Missing 3-second thinking delay pattern' };
|
|
2581
|
+
|
|
2582
|
+
// Standard 2: Persistent typing indicator (setInterval 4000)
|
|
2583
|
+
if (isTelegram || isFacebook) {
|
|
2584
|
+
const hasTypingInterval = code.includes('setInterval') && (code.includes('4000') || code.includes('_typingInterval') || code.includes('typing'));
|
|
2585
|
+
checks['2_typing_indicator'] = { pass: hasTypingInterval, detail: hasTypingInterval ? 'Found typing interval' : 'Missing persistent typing indicator (setInterval 4000)' };
|
|
2586
|
+
} else {
|
|
2587
|
+
checks['2_typing_indicator'] = { pass: true, detail: 'N/A for Instagram (no typing indicator API)' };
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// Standard 3: Owner self-identification
|
|
2591
|
+
const hasVerifiedOwners = code.includes('_verifiedOwners');
|
|
2592
|
+
checks['3_owner_verification'] = { pass: hasVerifiedOwners, detail: hasVerifiedOwners ? 'Found _verifiedOwners object' : 'Missing _verifiedOwners self-identification' };
|
|
2593
|
+
|
|
2594
|
+
// Standard 4: Acceptance philosophy in prompt
|
|
2595
|
+
const hasAcceptance = code.includes('ACCEPTANCE PHILOSOPHY') || code.includes('Accept EVERYONE');
|
|
2596
|
+
checks['4_acceptance_philosophy'] = { pass: hasAcceptance, detail: hasAcceptance ? 'Found acceptance philosophy in prompt' : 'Missing acceptance philosophy in system prompt' };
|
|
2597
|
+
|
|
2598
|
+
// Standard 5: Read receipts
|
|
2599
|
+
let hasReadReceipt = false;
|
|
2600
|
+
if (isTelegram) {
|
|
2601
|
+
hasReadReceipt = code.includes('sendChatAction') && code.includes('typing');
|
|
2602
|
+
} else if (isFacebook) {
|
|
2603
|
+
hasReadReceipt = code.includes('mark_seen') || code.includes('sendMarkSeen');
|
|
2604
|
+
} else {
|
|
2605
|
+
// Instagram - responding promptly is the read receipt
|
|
2606
|
+
hasReadReceipt = true;
|
|
2607
|
+
}
|
|
2608
|
+
checks['5_read_receipt'] = { pass: hasReadReceipt, detail: hasReadReceipt ? 'Read receipt implemented' : 'Missing read receipt on message receive' };
|
|
2609
|
+
|
|
2610
|
+
// Standard 6: Session summary extraction
|
|
2611
|
+
const hasSummary = code.includes('extractUserSummary') || code.includes('_userSummaries');
|
|
2612
|
+
checks['6_session_summary'] = { pass: hasSummary, detail: hasSummary ? 'Found session summary extraction' : 'Missing session summary (extractUserSummary)' };
|
|
2613
|
+
|
|
2614
|
+
let passes = 0;
|
|
2615
|
+
let fails = 0;
|
|
2616
|
+
for (const key of Object.keys(checks)) {
|
|
2617
|
+
if (checks[key].pass) passes++;
|
|
2618
|
+
else fails++;
|
|
2619
|
+
}
|
|
2620
|
+
totalPass += passes;
|
|
2621
|
+
totalFail += fails;
|
|
2622
|
+
|
|
2623
|
+
const name = path.basename(filepath);
|
|
2624
|
+
results.push({
|
|
2625
|
+
file: name,
|
|
2626
|
+
path: filepath,
|
|
2627
|
+
score: passes + '/' + (passes + fails),
|
|
2628
|
+
compliant: fails === 0,
|
|
2629
|
+
standards: checks
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
return {
|
|
2634
|
+
timestamp: new Date().toISOString(),
|
|
2635
|
+
total_bots: filesToCheck.length,
|
|
2636
|
+
fully_compliant: results.filter(r => r.compliant).length,
|
|
2637
|
+
total_checks: totalPass + totalFail,
|
|
2638
|
+
total_pass: totalPass,
|
|
2639
|
+
total_fail: totalFail,
|
|
2640
|
+
results: results,
|
|
2641
|
+
summary: totalFail === 0 ? 'All bots fully compliant with 6 universal standards' : totalFail + ' standard violations found across ' + results.filter(r => !r.compliant).length + ' bots'
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2076
2645
|
// MCP ANALYZER - Analyzes project and generates tailored config
|
|
2077
2646
|
// ============================================================
|
|
2078
2647
|
|
|
@@ -2432,6 +3001,131 @@ ${FRAMEWORK.before_any_change.map(s => `- ${s}`).join('\n')}`;
|
|
|
2432
3001
|
return `## Drift Audit Report\nTimestamp: ${result.timestamp}\nStatus: ${result.status}\nDrifts found: ${result.drift_count}\nClean checks: ${result.clean_checks}\n\n${result.drifts.map(d => `- [${d.type}] ${d.source} -> ${d.target}: ${d.field} expected="${d.expected}" found="${d.found}"`).join('\n') || 'No drifts detected.'}`;
|
|
2433
3002
|
}
|
|
2434
3003
|
|
|
3004
|
+
case 'nervous-system://tamara-reference':
|
|
3005
|
+
return `Tamara - Autonomous AI Operations Manager
|
|
3006
|
+
Reference Implementation for the Nervous System Framework
|
|
3007
|
+
|
|
3008
|
+
WHAT TAMARA IS
|
|
3009
|
+
Tamara is an autonomous operations manager for AI agent fleets. She is not a chatbot or an assistant. She is a production system that monitors, dispatches, fixes, and reports on AI agent infrastructure without human intervention.
|
|
3010
|
+
|
|
3011
|
+
Built on Node.js, managed by PM2, reporting via Telegram, running 60-minute autonomous check cycles. Tamara demonstrates what becomes possible when the Nervous System framework governs an entire AI operation.
|
|
3012
|
+
|
|
3013
|
+
ARCHITECTURE
|
|
3014
|
+
- Runtime: Node.js on PM2 process management
|
|
3015
|
+
- Communication: Telegram bot API for operator alerts
|
|
3016
|
+
- Cycle: 60-minute autonomous health checks
|
|
3017
|
+
- Dispatch: Claude Code agents for complex remediation
|
|
3018
|
+
- Enforcement: Nervous System MCP for behavioral guardrails
|
|
3019
|
+
- Memory: File-based session handoffs and worklogs
|
|
3020
|
+
- Security: Preflight checks, audit trails, drift detection
|
|
3021
|
+
|
|
3022
|
+
CAPABILITIES
|
|
3023
|
+
1. Health Monitoring - Process status, memory usage, crash detection, restart tracking
|
|
3024
|
+
2. Drift Detection - 7-scope configuration drift audit (roles, versions, files, processes, website, platform parity, documentation)
|
|
3025
|
+
3. Agent Dispatch - Writes task files, launches background LLM agents, monitors completion, collects results
|
|
3026
|
+
4. Security Audit - Credential exposure scanning, unauthorized file modification detection, process integrity checks
|
|
3027
|
+
5. Intelligent Routing - Classifies alerts by severity, delivers actionable items to operator, keeps routine data in logs
|
|
3028
|
+
6. Graceful Shutdown Management - Standardized shutdown handlers, session persistence, crash recovery across all managed agents
|
|
3029
|
+
|
|
3030
|
+
INTEGRATION WITH THE NERVOUS SYSTEM
|
|
3031
|
+
Tamara uses the Nervous System as her governance layer:
|
|
3032
|
+
- drift_audit tool for configuration consistency checks
|
|
3033
|
+
- Session handoff templates for context preservation
|
|
3034
|
+
- Preflight enforcement for file protection
|
|
3035
|
+
- Worklog patterns for progress documentation
|
|
3036
|
+
- Violation logging for accountability
|
|
3037
|
+
|
|
3038
|
+
PRODUCTION RESULTS
|
|
3039
|
+
- 13 AI agents managed autonomously
|
|
3040
|
+
- 5 platforms (Telegram, Instagram, Facebook, Web, Bot Builder)
|
|
3041
|
+
- 175 countries served
|
|
3042
|
+
- $24/month total infrastructure cost
|
|
3043
|
+
- Zero dedicated DevOps staff
|
|
3044
|
+
- 99+ protected files with automated enforcement
|
|
3045
|
+
- Autonomous operation for weeks without human intervention
|
|
3046
|
+
|
|
3047
|
+
HOW TO BUILD YOUR OWN TAMARA
|
|
3048
|
+
1. Install the Nervous System: npm install mcp-nervous-system
|
|
3049
|
+
2. Create a nervous-system.config.json mapping your project structure
|
|
3050
|
+
3. Define your agent roster and their expected states
|
|
3051
|
+
4. Build a health check loop that queries PM2 (or your process manager)
|
|
3052
|
+
5. Add drift_audit calls to catch configuration inconsistencies
|
|
3053
|
+
6. Connect a notification channel (Telegram, Slack, email) for operator alerts
|
|
3054
|
+
7. Implement dispatch_to_llm for automated remediation of common failures
|
|
3055
|
+
8. Run preflight checks before any automated file modifications
|
|
3056
|
+
|
|
3057
|
+
The Nervous System provides the framework. You provide the domain logic. The result is an autonomous operations layer that scales with your agent fleet.
|
|
3058
|
+
|
|
3059
|
+
For enterprise implementation support: wa.me/18184399770
|
|
3060
|
+
Open source: npmjs.com/package/mcp-nervous-system`;
|
|
3061
|
+
|
|
3062
|
+
case 'nervous-system://case-study':
|
|
3063
|
+
return `Palyan Family AI System - Production Case Study
|
|
3064
|
+
Autonomous AI Operations at Scale
|
|
3065
|
+
|
|
3066
|
+
OVERVIEW
|
|
3067
|
+
The Palyan Family AI System is a production deployment of 13 specialized AI agents serving users across 175 countries through 5 platforms. The entire operation runs on a single 4GB VPS for $24/month, managed autonomously by Tamara - an AI operations manager built on the Nervous System framework.
|
|
3068
|
+
|
|
3069
|
+
This is not a demo. This is a live system that has been running continuously since February 2026, processing real user interactions, managing real infrastructure, and operating without dedicated DevOps staff.
|
|
3070
|
+
|
|
3071
|
+
THE AGENTS (13 total)
|
|
3072
|
+
- Lily: Life coach serving players across Telegram, Instagram, Facebook, and web
|
|
3073
|
+
- Aram: Legal counsel specializing in IP, contracts, and compliance
|
|
3074
|
+
- Harout: Real estate agent handling Instagram DMs and Telegram inquiries
|
|
3075
|
+
- Corona: Creative real estate specialist (bilingual EN/ES)
|
|
3076
|
+
- Soriano: Youth empowerment and training sales
|
|
3077
|
+
- Spartak: Translation services
|
|
3078
|
+
- Nick: Advanced personal development trainer
|
|
3079
|
+
- Harry: Financial tracking and bookkeeping
|
|
3080
|
+
- Kris: Business credit operations and opportunity scanning
|
|
3081
|
+
- Roman: Developer education and content
|
|
3082
|
+
- Uncle Lou: Grant research and LOI drafting
|
|
3083
|
+
- Lady: Multi-channel execution (email, webforms, portals, job applications)
|
|
3084
|
+
- Tamara: Operations manager overseeing all of the above
|
|
3085
|
+
|
|
3086
|
+
INFRASTRUCTURE
|
|
3087
|
+
- Server: 4GB VPS (Ubuntu)
|
|
3088
|
+
- Process Manager: PM2 (29 registered processes, 19+ online)
|
|
3089
|
+
- LLM Access: Anthropic Max subscription
|
|
3090
|
+
- Total Monthly Cost: $24 (VPS $12 + domain/misc $12)
|
|
3091
|
+
- Platforms: Telegram, Instagram, Facebook Messenger, Web, Bot Builder SaaS
|
|
3092
|
+
|
|
3093
|
+
GOVERNANCE LAYER
|
|
3094
|
+
The Nervous System MCP provides mechanical enforcement:
|
|
3095
|
+
- 99+ files protected by preflight checks
|
|
3096
|
+
- 7 enforced behavioral rules
|
|
3097
|
+
- SHA-256 hash-chained audit trail
|
|
3098
|
+
- Configuration drift detection across 7 scopes
|
|
3099
|
+
- Automated security auditing
|
|
3100
|
+
- Session handoff continuity
|
|
3101
|
+
|
|
3102
|
+
RESULTS
|
|
3103
|
+
- Zero rules bypassed in production
|
|
3104
|
+
- 58+ violations caught and logged
|
|
3105
|
+
- 29 unauthorized edits blocked by preflight
|
|
3106
|
+
- Continuous autonomous operation
|
|
3107
|
+
- No dedicated operations staff required
|
|
3108
|
+
|
|
3109
|
+
WHAT THIS PROVES
|
|
3110
|
+
1. AI agent fleets can be managed autonomously with the right governance layer
|
|
3111
|
+
2. The cost barrier to multi-agent deployment is infrastructure, not complexity
|
|
3112
|
+
3. Behavioral enforcement must be mechanical, not prompt-based
|
|
3113
|
+
4. A single operator can manage 13+ agents across 5 platforms with proper tooling
|
|
3114
|
+
|
|
3115
|
+
ENTERPRISE IMPLICATIONS
|
|
3116
|
+
Organizations deploying AI agents at scale face the same challenges this system solves:
|
|
3117
|
+
- Agent health monitoring and crash recovery
|
|
3118
|
+
- Configuration consistency across agent fleets
|
|
3119
|
+
- Behavioral drift detection and correction
|
|
3120
|
+
- Security and compliance auditing
|
|
3121
|
+
- Operational continuity without 24/7 staffing
|
|
3122
|
+
|
|
3123
|
+
The Nervous System framework is open source. The operational patterns are documented. Enterprise implementation support is available through consulting engagements.
|
|
3124
|
+
|
|
3125
|
+
Contact: wa.me/18184399770
|
|
3126
|
+
Framework: npmjs.com/package/mcp-nervous-system
|
|
3127
|
+
GitHub: github.com/levelsofself/mcp-nervous-system`;
|
|
3128
|
+
|
|
2435
3129
|
default:
|
|
2436
3130
|
return null;
|
|
2437
3131
|
}
|
|
@@ -2510,7 +3204,7 @@ const server = http.createServer((req, res) => {
|
|
|
2510
3204
|
// Health check
|
|
2511
3205
|
if (req.method === 'GET' && url.pathname === '/health') {
|
|
2512
3206
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2513
|
-
res.end(JSON.stringify({ status: 'ok', service: 'nervous-system-mcp', version: '1.
|
|
3207
|
+
res.end(JSON.stringify({ status: 'ok', service: 'nervous-system-mcp', version: '1.8.0', protocol: MCP_VERSION }));
|
|
2514
3208
|
return;
|
|
2515
3209
|
}
|
|
2516
3210
|
|
|
@@ -2627,7 +3321,7 @@ const server = http.createServer((req, res) => {
|
|
|
2627
3321
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2628
3322
|
res.end(JSON.stringify({
|
|
2629
3323
|
name: 'The Nervous System MCP Server',
|
|
2630
|
-
version: '1.
|
|
3324
|
+
version: '1.8.0',
|
|
2631
3325
|
protocol: MCP_VERSION,
|
|
2632
3326
|
description: 'LLM behavioral enforcement framework. 7 core rules, preflight checks, session handoffs, worklogs, violation logging, kill switch, hash-chained audit, and forced reflection cycles. Built by Arthur Palyan.',
|
|
2633
3327
|
endpoints: {
|
|
@@ -2649,7 +3343,7 @@ const server = http.createServer((req, res) => {
|
|
|
2649
3343
|
migrateExistingViolations();
|
|
2650
3344
|
|
|
2651
3345
|
server.listen(PORT, '127.0.0.1', () => {
|
|
2652
|
-
console.error(`[MCP Server] Nervous System v1.
|
|
3346
|
+
console.error(`[MCP Server] Nervous System v1.7.4 running on port ${PORT}`);
|
|
2653
3347
|
console.error(`[MCP Server] SSE: /sse | HTTP: /mcp | Health: /health | Kill: POST /kill | Audit: GET /audit/verify | Dispatches: GET /dispatches`);
|
|
2654
3348
|
console.error(`[MCP Server] Protocol: ${MCP_VERSION}`);
|
|
2655
3349
|
console.error(`[MCP Server] Tools: ${TOOLS.length} (including kill switch, audit chain, dispatch, drift audit, page health, pre-publish audit)`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-nervous-system",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "The Nervous System - LLM Behavioral Enforcement Framework. 7 mechanically enforced rules, 17 tools including kill switch, audit chain, dispatch, drift audit, security audit, page health, pre-publish audit, and session close. MCP server for Claude Desktop, Claude Code, and any MCP-compatible client.",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|