ruvnet-kb-first 5.0.0
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/LICENSE +21 -0
- package/README.md +674 -0
- package/SKILL.md +740 -0
- package/bin/kb-first.js +123 -0
- package/install/init-project.sh +435 -0
- package/install/install-global.sh +257 -0
- package/install/kb-first-autodetect.sh +108 -0
- package/install/kb-first-command.md +80 -0
- package/install/kb-first-skill.md +262 -0
- package/package.json +87 -0
- package/phases/00-assessment.md +529 -0
- package/phases/01-storage.md +194 -0
- package/phases/01.5-hooks-setup.md +521 -0
- package/phases/02-kb-creation.md +413 -0
- package/phases/03-persistence.md +125 -0
- package/phases/04-visualization.md +170 -0
- package/phases/05-integration.md +114 -0
- package/phases/06-scaffold.md +130 -0
- package/phases/07-build.md +493 -0
- package/phases/08-verification.md +597 -0
- package/phases/09-security.md +512 -0
- package/phases/10-documentation.md +613 -0
- package/phases/11-deployment.md +670 -0
- package/phases/testing.md +713 -0
- package/scripts/1.5-hooks-verify.sh +252 -0
- package/scripts/8.1-code-scan.sh +58 -0
- package/scripts/8.2-import-check.sh +42 -0
- package/scripts/8.3-source-returns.sh +52 -0
- package/scripts/8.4-startup-verify.sh +65 -0
- package/scripts/8.5-fallback-check.sh +63 -0
- package/scripts/8.6-attribution.sh +56 -0
- package/scripts/8.7-confidence.sh +56 -0
- package/scripts/8.8-gap-logging.sh +70 -0
- package/scripts/9-security-audit.sh +202 -0
- package/scripts/init-project.sh +395 -0
- package/scripts/verify-enforcement.sh +167 -0
- package/src/commands/hooks.js +361 -0
- package/src/commands/init.js +315 -0
- package/src/commands/phase.js +372 -0
- package/src/commands/score.js +380 -0
- package/src/commands/status.js +193 -0
- package/src/commands/verify.js +286 -0
- package/src/index.js +56 -0
- package/src/mcp-server.js +412 -0
- package/templates/attention-router.ts +534 -0
- package/templates/code-analysis.ts +683 -0
- package/templates/federated-kb-learner.ts +649 -0
- package/templates/gnn-engine.ts +1091 -0
- package/templates/intentions.md +277 -0
- package/templates/kb-client.ts +905 -0
- package/templates/schema.sql +303 -0
- package/templates/sona-config.ts +312 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Phase 1: Storage Setup
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Ensure persistent storage is available before any KB work begins. The KB must survive restarts, be queryable, and support vector embeddings.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Docker installed
|
|
12
|
+
- Port 5432 available (or choose different port)
|
|
13
|
+
- ~1GB disk space for initial setup
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1.1 Check for Running Storage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
docker ps | grep ruvector-db
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**If found:** Skip to Step 1.3
|
|
26
|
+
**If not found:** Continue to Step 1.2
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### 1.2 Start Persistent Storage
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Create data directory for persistence
|
|
34
|
+
mkdir -p ~/ruvector-data
|
|
35
|
+
|
|
36
|
+
# Start RuVector PostgreSQL
|
|
37
|
+
docker run -d \
|
|
38
|
+
--name ruvector-db \
|
|
39
|
+
--restart unless-stopped \
|
|
40
|
+
-e POSTGRES_PASSWORD=${RUVECTOR_PASSWORD:-ruvector_secure_2024} \
|
|
41
|
+
-p 5432:5432 \
|
|
42
|
+
-v ~/ruvector-data:/var/lib/postgresql/data \
|
|
43
|
+
ruvnet/ruvector-postgres:latest
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Wait for container to be healthy:
|
|
47
|
+
```bash
|
|
48
|
+
echo "Waiting for PostgreSQL to be ready..."
|
|
49
|
+
until docker exec ruvector-db pg_isready -U postgres 2>/dev/null; do
|
|
50
|
+
sleep 2
|
|
51
|
+
echo "Still waiting..."
|
|
52
|
+
done
|
|
53
|
+
echo "PostgreSQL is ready!"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Alternative: Standard pgvector**
|
|
57
|
+
|
|
58
|
+
If ruvector-postgres is unavailable:
|
|
59
|
+
```bash
|
|
60
|
+
docker run -d \
|
|
61
|
+
--name ruvector-db \
|
|
62
|
+
--restart unless-stopped \
|
|
63
|
+
-e POSTGRES_PASSWORD=${RUVECTOR_PASSWORD:-ruvector_secure_2024} \
|
|
64
|
+
-p 5432:5432 \
|
|
65
|
+
-v ~/ruvector-data:/var/lib/postgresql/data \
|
|
66
|
+
pgvector/pgvector:pg16
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### 1.3 Verify Connection
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Set environment variable
|
|
75
|
+
export DATABASE_URL="postgresql://postgres:${RUVECTOR_PASSWORD:-ruvector_secure_2024}@localhost:5432/postgres"
|
|
76
|
+
|
|
77
|
+
# Test connection
|
|
78
|
+
psql "$DATABASE_URL" -c "SELECT 1" || {
|
|
79
|
+
echo "ERROR: Could not connect to database"
|
|
80
|
+
exit 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
echo "Connection successful!"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### 1.4 Initialize Schema
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Run the schema initialization
|
|
92
|
+
psql "$DATABASE_URL" -f templates/schema.sql
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**What the schema creates:**
|
|
96
|
+
- `kb_nodes` — Knowledge content with embeddings
|
|
97
|
+
- `kb_gaps` — Unanswered queries for KB improvement
|
|
98
|
+
- `kb_analytics` — Usage tracking
|
|
99
|
+
- `reasoning_bank` — SONA pattern storage
|
|
100
|
+
- `gnn_nodes` and `gnn_edges` — Graph structure (if using GNN)
|
|
101
|
+
- `attention_experts` — Expert routing (if using MoE)
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 1.5 Set Environment Variables
|
|
106
|
+
|
|
107
|
+
Add to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
export DATABASE_URL="postgresql://postgres:${RUVECTOR_PASSWORD:-ruvector_secure_2024}@localhost:5432/postgres"
|
|
111
|
+
export RUVECTOR_STORAGE="postgres"
|
|
112
|
+
export RUVECTOR_EMBEDDING_MODEL="all-MiniLM-L6-v2"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Reload:
|
|
116
|
+
```bash
|
|
117
|
+
source ~/.bashrc # or ~/.zshrc
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### 1.6 Verify Extensions
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
psql "$DATABASE_URL" -c "SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'ruvector', 'pg_trgm');"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Expected output:
|
|
129
|
+
```
|
|
130
|
+
extname | extversion
|
|
131
|
+
----------+------------
|
|
132
|
+
vector | 0.7.0
|
|
133
|
+
pg_trgm | 1.6
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If `ruvector` is available (using ruvector-postgres):
|
|
137
|
+
```
|
|
138
|
+
extname | extversion
|
|
139
|
+
----------+------------
|
|
140
|
+
ruvector | 0.2.0
|
|
141
|
+
pg_trgm | 1.6
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Quality Gate Checklist
|
|
147
|
+
|
|
148
|
+
Before proceeding to Phase 2, verify:
|
|
149
|
+
|
|
150
|
+
- [ ] `docker ps | grep ruvector-db` shows running container
|
|
151
|
+
- [ ] `psql "$DATABASE_URL" -c "SELECT 1"` succeeds
|
|
152
|
+
- [ ] Schema tables exist: `psql "$DATABASE_URL" -c "\dt kb_*"`
|
|
153
|
+
- [ ] Vector extension active: `SELECT extname FROM pg_extension WHERE extname = 'vector';`
|
|
154
|
+
- [ ] Environment variables set
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Troubleshooting
|
|
159
|
+
|
|
160
|
+
### "Connection refused"
|
|
161
|
+
```bash
|
|
162
|
+
# Check if container is running
|
|
163
|
+
docker ps -a | grep ruvector-db
|
|
164
|
+
|
|
165
|
+
# Check logs
|
|
166
|
+
docker logs ruvector-db
|
|
167
|
+
|
|
168
|
+
# Restart if needed
|
|
169
|
+
docker restart ruvector-db
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### "Permission denied"
|
|
173
|
+
```bash
|
|
174
|
+
# Fix data directory permissions
|
|
175
|
+
sudo chown -R $(id -u):$(id -g) ~/ruvector-data
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### "Port already in use"
|
|
179
|
+
```bash
|
|
180
|
+
# Find what's using the port
|
|
181
|
+
lsof -i :5432
|
|
182
|
+
|
|
183
|
+
# Or use a different port
|
|
184
|
+
docker run -d --name ruvector-db ... -p 5433:5432 ...
|
|
185
|
+
export DATABASE_URL="postgresql://postgres:...@localhost:5433/postgres"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Exit Criteria
|
|
191
|
+
|
|
192
|
+
Storage is running, accessible, and schema is initialized.
|
|
193
|
+
|
|
194
|
+
**Proceed to Phase 2: KB Creation**
|
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
# Phase 1.5: RuVector Hooks Setup
|
|
2
|
+
|
|
3
|
+
Updated: 2026-01-01 23:45:00 EST | Version 1.0.0
|
|
4
|
+
Created: 2026-01-01 23:45:00 EST
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Configure Claude Code hooks for automatic KB enforcement. Hooks ensure KB-First rules are followed throughout development by intercepting tool calls and enforcing KB consultation.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- Phase 1 complete (storage running and verified)
|
|
15
|
+
- Claude Code installed
|
|
16
|
+
- `~/.claude/` directory exists
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Why Hooks Are Critical
|
|
21
|
+
|
|
22
|
+
Without hooks, KB-First is an honor system. Developers (or Claude) can bypass KB at any time:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Without hooks, nothing stops this:
|
|
26
|
+
const rate = 0.04; // Hardcoded - VIOLATION!
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
With hooks installed, every Write/Edit/Bash call is intercepted:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
PreToolUse Hook → Check KB for relevant content → Inject context or warn
|
|
33
|
+
PostToolUse Hook → Record outcome → Trigger SONA learning
|
|
34
|
+
SessionEnd Hook → Persist patterns → Consolidate learning
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Sub-Phases
|
|
40
|
+
|
|
41
|
+
| Sub-Phase | Name | Purpose |
|
|
42
|
+
|-----------|------|---------|
|
|
43
|
+
| 1.5.1 | Install Hooks | Install RuVector hook scripts |
|
|
44
|
+
| 1.5.2 | Configure Settings | Update ~/.claude/settings.json |
|
|
45
|
+
| 1.5.3 | Pre-train ReasoningBank | Seed patterns for KB enforcement |
|
|
46
|
+
| 1.5.4 | Verify Functionality | Test hooks fire correctly |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 1.5.1 Install Hooks
|
|
51
|
+
|
|
52
|
+
### Option A: RuVector CLI (Recommended)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Initialize hooks directory and scripts
|
|
56
|
+
npx @ruvector/cli hooks init
|
|
57
|
+
|
|
58
|
+
# Install to Claude Code settings
|
|
59
|
+
npx @ruvector/cli hooks install
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This creates:
|
|
63
|
+
- `~/.claude/hooks/pre_tool_use.py`
|
|
64
|
+
- `~/.claude/hooks/post_tool_use.py`
|
|
65
|
+
- `~/.claude/hooks/session_end.py`
|
|
66
|
+
|
|
67
|
+
### Option B: Manual Installation
|
|
68
|
+
|
|
69
|
+
Create `~/.claude/hooks/` directory:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
mkdir -p ~/.claude/hooks
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Create `~/.claude/hooks/pre_tool_use.py`:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
#!/usr/bin/env python3
|
|
79
|
+
"""
|
|
80
|
+
RuVector PreToolUse Hook
|
|
81
|
+
Checks KB before every tool call
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
import json
|
|
85
|
+
import sys
|
|
86
|
+
import subprocess
|
|
87
|
+
import os
|
|
88
|
+
|
|
89
|
+
def main():
|
|
90
|
+
try:
|
|
91
|
+
input_data = json.load(sys.stdin)
|
|
92
|
+
tool_name = input_data.get('tool_name', '')
|
|
93
|
+
tool_input = input_data.get('tool_input', {})
|
|
94
|
+
|
|
95
|
+
# Skip non-writing operations
|
|
96
|
+
if tool_name not in ('Edit', 'Write', 'MultiEdit'):
|
|
97
|
+
print(json.dumps({"decision": "continue"}))
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
file_path = tool_input.get('file_path', '')
|
|
101
|
+
|
|
102
|
+
# Only check domain files
|
|
103
|
+
if '/domain/' not in file_path and '/src/' not in file_path:
|
|
104
|
+
print(json.dumps({"decision": "continue"}))
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# Query KB for relevant context
|
|
108
|
+
query = extract_query(file_path, tool_input)
|
|
109
|
+
if query:
|
|
110
|
+
kb_results = search_kb(query)
|
|
111
|
+
if kb_results:
|
|
112
|
+
guidance = format_guidance(kb_results)
|
|
113
|
+
print(json.dumps({
|
|
114
|
+
"decision": "continue",
|
|
115
|
+
"message": guidance
|
|
116
|
+
}))
|
|
117
|
+
else:
|
|
118
|
+
log_gap(query)
|
|
119
|
+
print(json.dumps({
|
|
120
|
+
"decision": "continue",
|
|
121
|
+
"message": f"⚠️ No KB content for: {query[:80]}..."
|
|
122
|
+
}))
|
|
123
|
+
else:
|
|
124
|
+
print(json.dumps({"decision": "continue"}))
|
|
125
|
+
|
|
126
|
+
except Exception as e:
|
|
127
|
+
# Fail open - don't block on hook errors
|
|
128
|
+
print(json.dumps({"decision": "continue"}))
|
|
129
|
+
|
|
130
|
+
def extract_query(file_path, tool_input):
|
|
131
|
+
"""Extract searchable query from file path and content"""
|
|
132
|
+
parts = file_path.split('/')
|
|
133
|
+
relevant = [p for p in parts if p not in ('src', 'domain', 'lib')]
|
|
134
|
+
return ' '.join(relevant).replace('.ts', '').replace('.js', '')
|
|
135
|
+
|
|
136
|
+
def search_kb(query):
|
|
137
|
+
"""Search KB via RuVector CLI"""
|
|
138
|
+
try:
|
|
139
|
+
result = subprocess.run(
|
|
140
|
+
['npx', '@ruvector/cli', 'search', '--query', query, '--limit', '3', '--json'],
|
|
141
|
+
capture_output=True, text=True, timeout=3
|
|
142
|
+
)
|
|
143
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
144
|
+
return json.loads(result.stdout)
|
|
145
|
+
except:
|
|
146
|
+
pass
|
|
147
|
+
return []
|
|
148
|
+
|
|
149
|
+
def format_guidance(results):
|
|
150
|
+
"""Format KB results as guidance"""
|
|
151
|
+
lines = ["📚 KB Context:"]
|
|
152
|
+
for r in results[:3]:
|
|
153
|
+
title = r.get('title', 'Unknown')
|
|
154
|
+
conf = r.get('confidence', 0)
|
|
155
|
+
lines.append(f" • {title} ({conf:.0%})")
|
|
156
|
+
return '\n'.join(lines)
|
|
157
|
+
|
|
158
|
+
def log_gap(query):
|
|
159
|
+
"""Log query that found no KB results"""
|
|
160
|
+
try:
|
|
161
|
+
subprocess.run(
|
|
162
|
+
['npx', '@ruvector/cli', 'log-gap', '--query', query[:500]],
|
|
163
|
+
capture_output=True, timeout=2
|
|
164
|
+
)
|
|
165
|
+
except:
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
if __name__ == '__main__':
|
|
169
|
+
main()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Create `~/.claude/hooks/post_tool_use.py`:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
#!/usr/bin/env python3
|
|
176
|
+
"""
|
|
177
|
+
RuVector PostToolUse Hook
|
|
178
|
+
Records outcomes and triggers SONA learning
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
import json
|
|
182
|
+
import sys
|
|
183
|
+
import subprocess
|
|
184
|
+
|
|
185
|
+
def main():
|
|
186
|
+
try:
|
|
187
|
+
input_data = json.load(sys.stdin)
|
|
188
|
+
tool_name = input_data.get('tool_name', '')
|
|
189
|
+
success = input_data.get('success', True)
|
|
190
|
+
|
|
191
|
+
# Record outcome
|
|
192
|
+
record_outcome(tool_name, success)
|
|
193
|
+
|
|
194
|
+
# Trigger SONA learning on success
|
|
195
|
+
if success and tool_name in ('Edit', 'Write'):
|
|
196
|
+
trigger_learning(tool_name)
|
|
197
|
+
|
|
198
|
+
except:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
print(json.dumps({"decision": "continue"}))
|
|
202
|
+
|
|
203
|
+
def record_outcome(tool_name, success):
|
|
204
|
+
try:
|
|
205
|
+
subprocess.run([
|
|
206
|
+
'npx', '@ruvector/cli', 'record-outcome',
|
|
207
|
+
'--tool', tool_name,
|
|
208
|
+
'--success', str(success).lower()
|
|
209
|
+
], capture_output=True, timeout=2)
|
|
210
|
+
except:
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def trigger_learning(tool_name):
|
|
214
|
+
try:
|
|
215
|
+
subprocess.run([
|
|
216
|
+
'npx', '@ruvector/cli', 'sona', 'learn',
|
|
217
|
+
'--tool', tool_name,
|
|
218
|
+
'--outcome', 'positive'
|
|
219
|
+
], capture_output=True, timeout=2)
|
|
220
|
+
except:
|
|
221
|
+
pass
|
|
222
|
+
|
|
223
|
+
if __name__ == '__main__':
|
|
224
|
+
main()
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Create `~/.claude/hooks/session_end.py`:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
#!/usr/bin/env python3
|
|
231
|
+
"""
|
|
232
|
+
RuVector SessionEnd Hook
|
|
233
|
+
Persists learned patterns
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
import json
|
|
237
|
+
import sys
|
|
238
|
+
import subprocess
|
|
239
|
+
|
|
240
|
+
def main():
|
|
241
|
+
try:
|
|
242
|
+
input_data = json.load(sys.stdin)
|
|
243
|
+
session_id = input_data.get('session_id', 'unknown')
|
|
244
|
+
|
|
245
|
+
# Checkpoint SONA state
|
|
246
|
+
subprocess.run([
|
|
247
|
+
'npx', '@ruvector/cli', 'sona', 'checkpoint',
|
|
248
|
+
'--session', session_id
|
|
249
|
+
], capture_output=True, timeout=5)
|
|
250
|
+
|
|
251
|
+
# Consolidate patterns
|
|
252
|
+
subprocess.run([
|
|
253
|
+
'npx', '@ruvector/cli', 'sona', 'consolidate'
|
|
254
|
+
], capture_output=True, timeout=10)
|
|
255
|
+
|
|
256
|
+
except:
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
print(json.dumps({"decision": "continue"}))
|
|
260
|
+
|
|
261
|
+
if __name__ == '__main__':
|
|
262
|
+
main()
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Make hooks executable:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
chmod +x ~/.claude/hooks/*.py
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 1.5.2 Configure Settings
|
|
274
|
+
|
|
275
|
+
Update `~/.claude/settings.json` to register hooks:
|
|
276
|
+
|
|
277
|
+
### Option A: RuVector CLI
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
npx @ruvector/cli hooks configure
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Option B: Manual Configuration
|
|
284
|
+
|
|
285
|
+
Edit `~/.claude/settings.json`:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"hooks": {
|
|
290
|
+
"PreToolUse": [
|
|
291
|
+
{
|
|
292
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
293
|
+
"hooks": [
|
|
294
|
+
{
|
|
295
|
+
"type": "command",
|
|
296
|
+
"command": "python3 ~/.claude/hooks/pre_tool_use.py"
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
"PostToolUse": [
|
|
302
|
+
{
|
|
303
|
+
"matcher": "*",
|
|
304
|
+
"hooks": [
|
|
305
|
+
{
|
|
306
|
+
"type": "command",
|
|
307
|
+
"command": "python3 ~/.claude/hooks/post_tool_use.py"
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
"SessionEnd": [
|
|
313
|
+
{
|
|
314
|
+
"matcher": "*",
|
|
315
|
+
"hooks": [
|
|
316
|
+
{
|
|
317
|
+
"type": "command",
|
|
318
|
+
"command": "python3 ~/.claude/hooks/session_end.py"
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Verify configuration:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
cat ~/.claude/settings.json | jq '.hooks'
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 1.5.3 Pre-train ReasoningBank
|
|
336
|
+
|
|
337
|
+
The ReasoningBank stores patterns that hooks use to provide guidance. Pre-training seeds it with KB-First enforcement patterns.
|
|
338
|
+
|
|
339
|
+
### Option A: RuVector CLI
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Pre-train with KB-First patterns
|
|
343
|
+
npx @ruvector/cli reasoningbank seed --kb-first
|
|
344
|
+
|
|
345
|
+
# Or seed from this repository
|
|
346
|
+
npx @ruvector/cli reasoningbank import ./patterns/kb-first-patterns.json
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Option B: Manual Seeding
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# Connect to ReasoningBank database
|
|
353
|
+
export REASONING_BANK_DB=".swarm/memory.db"
|
|
354
|
+
|
|
355
|
+
# Seed KB-First patterns
|
|
356
|
+
sqlite3 "$REASONING_BANK_DB" << 'EOF'
|
|
357
|
+
INSERT INTO reasoning_memory (id, title, content, namespace, created_at)
|
|
358
|
+
VALUES
|
|
359
|
+
(lower(hex(randomblob(16))), 'kb/enforcement/no-hardcode',
|
|
360
|
+
'Never hardcode domain values. Always query KB: const rate = await kb.search("rate")',
|
|
361
|
+
'kb_first_patterns', datetime('now')),
|
|
362
|
+
(lower(hex(randomblob(16))), 'kb/enforcement/source-return',
|
|
363
|
+
'All domain functions must return kbSources array for traceability',
|
|
364
|
+
'kb_first_patterns', datetime('now')),
|
|
365
|
+
(lower(hex(randomblob(16))), 'kb/enforcement/startup-verify',
|
|
366
|
+
'Entry point must verify KB connection with process.exit(1) on failure',
|
|
367
|
+
'kb_first_patterns', datetime('now')),
|
|
368
|
+
(lower(hex(randomblob(16))), 'kb/enforcement/no-fallback',
|
|
369
|
+
'Never use fallback defaults: const x = kbValue || DEFAULT is forbidden',
|
|
370
|
+
'kb_first_patterns', datetime('now')),
|
|
371
|
+
(lower(hex(randomblob(16))), 'kb/enforcement/expert-attribution',
|
|
372
|
+
'All KB nodes must have source_expert field with expert name',
|
|
373
|
+
'kb_first_patterns', datetime('now'));
|
|
374
|
+
EOF
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Verify seeding:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
sqlite3 "$REASONING_BANK_DB" "SELECT title FROM reasoning_memory WHERE namespace = 'kb_first_patterns';"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Expected output:
|
|
384
|
+
```
|
|
385
|
+
kb/enforcement/no-hardcode
|
|
386
|
+
kb/enforcement/source-return
|
|
387
|
+
kb/enforcement/startup-verify
|
|
388
|
+
kb/enforcement/no-fallback
|
|
389
|
+
kb/enforcement/expert-attribution
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## 1.5.4 Verify Functionality
|
|
395
|
+
|
|
396
|
+
### Test 1: Hooks Are Registered
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
cat ~/.claude/settings.json | jq '.hooks | keys'
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Expected output:
|
|
403
|
+
```json
|
|
404
|
+
[
|
|
405
|
+
"PreToolUse",
|
|
406
|
+
"PostToolUse",
|
|
407
|
+
"SessionEnd"
|
|
408
|
+
]
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Test 2: Hook Scripts Exist and Are Executable
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
ls -la ~/.claude/hooks/*.py
|
|
415
|
+
|
|
416
|
+
# Test syntax
|
|
417
|
+
python3 -m py_compile ~/.claude/hooks/pre_tool_use.py
|
|
418
|
+
python3 -m py_compile ~/.claude/hooks/post_tool_use.py
|
|
419
|
+
python3 -m py_compile ~/.claude/hooks/session_end.py
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Test 3: PreToolUse Hook Fires
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Simulate hook input
|
|
426
|
+
echo '{"tool_name": "Write", "tool_input": {"file_path": "src/domain/calculator.ts"}}' | \
|
|
427
|
+
python3 ~/.claude/hooks/pre_tool_use.py
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Expected output (JSON with decision):
|
|
431
|
+
```json
|
|
432
|
+
{"decision": "continue", "message": "..."}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
or
|
|
436
|
+
|
|
437
|
+
```json
|
|
438
|
+
{"decision": "continue"}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Test 4: ReasoningBank Has Patterns
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
sqlite3 .swarm/memory.db "SELECT COUNT(*) FROM reasoning_memory WHERE namespace = 'kb_first_patterns';"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Expected: `≥5`
|
|
448
|
+
|
|
449
|
+
### Test 5: End-to-End Verification
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
# Run the verification script
|
|
453
|
+
./scripts/1.5-hooks-verify.sh
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Quality Gate Checklist
|
|
459
|
+
|
|
460
|
+
Before proceeding to Phase 2, verify:
|
|
461
|
+
|
|
462
|
+
- [ ] Hook scripts exist in `~/.claude/hooks/`
|
|
463
|
+
- [ ] Hooks are registered in `~/.claude/settings.json`
|
|
464
|
+
- [ ] ReasoningBank has KB-First patterns (≥5 entries)
|
|
465
|
+
- [ ] PreToolUse hook returns valid JSON
|
|
466
|
+
- [ ] All hook scripts pass syntax check
|
|
467
|
+
- [ ] `./scripts/1.5-hooks-verify.sh` returns PASS
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Troubleshooting
|
|
472
|
+
|
|
473
|
+
### Hooks Not Firing
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Check Claude Code version supports hooks
|
|
477
|
+
claude --version
|
|
478
|
+
|
|
479
|
+
# Verify settings.json is valid JSON
|
|
480
|
+
python3 -c "import json; json.load(open('$HOME/.claude/settings.json'))"
|
|
481
|
+
|
|
482
|
+
# Check file permissions
|
|
483
|
+
ls -la ~/.claude/hooks/
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### "Command not found: python3"
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
# macOS
|
|
490
|
+
brew install python3
|
|
491
|
+
|
|
492
|
+
# Ubuntu
|
|
493
|
+
sudo apt install python3
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Hook Timeouts
|
|
497
|
+
|
|
498
|
+
Hooks have a timeout. If KB search is slow:
|
|
499
|
+
|
|
500
|
+
1. Check DATABASE_URL is set correctly
|
|
501
|
+
2. Verify PostgreSQL is running
|
|
502
|
+
3. Consider increasing timeout in hook scripts
|
|
503
|
+
|
|
504
|
+
### ReasoningBank Empty
|
|
505
|
+
|
|
506
|
+
```bash
|
|
507
|
+
# Initialize ReasoningBank
|
|
508
|
+
npx claude-flow memory init
|
|
509
|
+
|
|
510
|
+
# Or create manually
|
|
511
|
+
mkdir -p .swarm
|
|
512
|
+
sqlite3 .swarm/memory.db "CREATE TABLE IF NOT EXISTS reasoning_memory (id TEXT PRIMARY KEY, title TEXT, content TEXT, namespace TEXT, created_at TEXT);"
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Exit Criteria
|
|
518
|
+
|
|
519
|
+
Hooks are installed, configured, pre-trained, and verified working.
|
|
520
|
+
|
|
521
|
+
**Proceed to Phase 2: KB Creation**
|