@adaptic/maestro 1.1.6 → 1.1.8
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/commands/init-maestro.md +225 -279
- package/README.md +19 -2
- package/docs/guides/email-setup.md +399 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/outbound-governance-setup.md +438 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +550 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/slack-setup.md +348 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/whatsapp-setup.md +282 -0
- package/docs/runbooks/mac-mini-bootstrap.md +21 -0
- package/package.json +1 -1
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scripts/media-generation/README.md +2 -0
- package/scripts/pdf-generation/README.md +2 -0
- package/scripts/poller/slack-poller.mjs +22 -7
- package/scripts/poller/trigger.mjs +12 -1
- package/scripts/setup/boot-claude-session.sh +4 -8
- package/scripts/setup/configure-macos.sh +8 -4
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# RAG & Context Retrieval Setup Guide
|
|
2
|
+
|
|
3
|
+
How the agent's memory and context retrieval system works: the SQLite FTS5 search index, per-user access-scoped search, pre-draft context enrichment, post-interaction entity extraction, and the integration points with every send script.
|
|
4
|
+
|
|
5
|
+
**Prerequisites**: Complete the [Mac Mini Bootstrap](../runbooks/mac-mini-bootstrap.md). The RAG system uses only Python standard library plus optional PyYAML — no vector database or embedding API required.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Architecture Overview
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
13
|
+
│ INDEXING (write path) │
|
|
14
|
+
│ │
|
|
15
|
+
│ ┌──────────────────────┐ ┌─────────────────────────────────┐ │
|
|
16
|
+
│ │ rag-indexer.py │───▶│ state/rag/search.db │ │
|
|
17
|
+
│ │ (incremental FTS5) │ │ (SQLite FTS5 full-text search) │ │
|
|
18
|
+
│ └──────────────────────┘ └─────────────────────────────────┘ │
|
|
19
|
+
│ ▲ │
|
|
20
|
+
│ │ sources: │
|
|
21
|
+
│ ├── memory/interactions/**/*.jsonl (Slack, email, calls) │
|
|
22
|
+
│ ├── knowledge/sources/*.yaml (public knowledge) │
|
|
23
|
+
│ ├── knowledge/decisions/*.yaml (leadership+) │
|
|
24
|
+
│ ├── knowledge/syntheses/*.yaml (strategy = ceo-only) │
|
|
25
|
+
│ └── state/queues/*.yaml (leadership+) │
|
|
26
|
+
│ │
|
|
27
|
+
│ ┌──────────────────────┐ ┌─────────────────────────────────┐ │
|
|
28
|
+
│ │ post-interaction- │───▶│ memory/indexes/ │ │
|
|
29
|
+
│ │ indexer.py │ │ entity-relationships.yaml │ │
|
|
30
|
+
│ │ (entity extraction) │ │ (people, orgs, topics, facts) │ │
|
|
31
|
+
│ └──────────────────────┘ └─────────────────────────────────┘ │
|
|
32
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
33
|
+
│ RETRIEVAL (read path) │
|
|
34
|
+
│ │
|
|
35
|
+
│ ┌──────────────────────┐ ┌─────────────────────────────────┐ │
|
|
36
|
+
│ │ user-context-search │◀──│ config/caller-id-map.yaml │ │
|
|
37
|
+
│ │ .py │ │ (user → access level mapping) │ │
|
|
38
|
+
│ │ (grep or sqlite) │ └─────────────────────────────────┘ │
|
|
39
|
+
│ └──────────────────────┘ │
|
|
40
|
+
│ │
|
|
41
|
+
│ ┌──────────────────────┐ ┌─────────────────────────────────┐ │
|
|
42
|
+
│ │ pre-draft-context.py │───▶│ Entity context for recipient │ │
|
|
43
|
+
│ │ (fact retrieval) │ │ (< 500ms, file reads only) │ │
|
|
44
|
+
│ └──────────────────────┘ └─────────────────────────────────┘ │
|
|
45
|
+
│ │ │
|
|
46
|
+
│ ▼ │
|
|
47
|
+
│ ┌──────────────────────┐ Integrated into every send script: │
|
|
48
|
+
│ │ pre_draft_lookup.py │ send-email-threaded.py, slack-send.sh │
|
|
49
|
+
│ │ (wrapper + audit log) │ send-whatsapp.sh, send-sms.sh │
|
|
50
|
+
│ └──────────────────────┘ │
|
|
51
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Key design choice**: The RAG system uses **SQLite FTS5** (full-text search) rather than vector embeddings. This means zero external dependencies, sub-millisecond search latency, no API calls during retrieval, and a database that's a single file you can back up with `cp`. The trade-off is keyword-based matching rather than semantic search — but for structured operational data (names, topics, dates), keyword search is more reliable.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 1. The Search Index (`rag-indexer.py`)
|
|
59
|
+
|
|
60
|
+
### 1.1 What It Indexes
|
|
61
|
+
|
|
62
|
+
| Source | Path Pattern | User Scope | Content |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| Interactions | `memory/interactions/**/*.jsonl` | Per-user (DMs) or channel-scoped | Slack messages, emails, call transcripts |
|
|
65
|
+
| Public knowledge | `knowledge/sources/*.yaml` | `public` | Company facts, product info |
|
|
66
|
+
| Decisions | `knowledge/decisions/*.yaml` | `leadership` | Strategic decisions with rationale |
|
|
67
|
+
| Syntheses | `knowledge/syntheses/*.yaml` | `public` (except strategy-state = `ceo`) | Analysis summaries |
|
|
68
|
+
| Queues | `state/queues/*.yaml` | `leadership` | Action items, follow-ups, blockers |
|
|
69
|
+
|
|
70
|
+
### 1.2 User Scope (Ring-Fencing)
|
|
71
|
+
|
|
72
|
+
Every indexed document gets a `user_scope` that controls who can retrieve it:
|
|
73
|
+
|
|
74
|
+
| Scope | Visible To | Example Content |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `public` | All authenticated users | Company overview, public knowledge |
|
|
77
|
+
| `leadership` | Leadership + CEO | Decisions, queue items, internal docs |
|
|
78
|
+
| `ceo` | CEO only | Strategy state, all interactions, all logs |
|
|
79
|
+
| `{user-slug}` | That specific user only | Their DMs, their emails |
|
|
80
|
+
|
|
81
|
+
This ensures that when the agent is on a voice call with a partner, it can't accidentally surface confidential CEO-only information.
|
|
82
|
+
|
|
83
|
+
### 1.3 Database Schema
|
|
84
|
+
|
|
85
|
+
SQLite database at `state/rag/search.db`:
|
|
86
|
+
|
|
87
|
+
```sql
|
|
88
|
+
-- Main document table
|
|
89
|
+
documents (
|
|
90
|
+
id TEXT PRIMARY KEY, -- SHA-256 hash of source_path + content
|
|
91
|
+
source_type TEXT NOT NULL, -- "interaction", "knowledge", "decision", etc.
|
|
92
|
+
source_path TEXT NOT NULL, -- Relative path to source file
|
|
93
|
+
user_scope TEXT NOT NULL, -- Access scope (public, leadership, ceo, user-slug)
|
|
94
|
+
content TEXT NOT NULL, -- Full text content
|
|
95
|
+
title TEXT, -- Document title (if available)
|
|
96
|
+
timestamp TEXT, -- ISO 8601 timestamp
|
|
97
|
+
metadata_json TEXT -- Additional metadata as JSON
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
-- FTS5 virtual table (full-text search)
|
|
101
|
+
documents_fts USING fts5(content, title);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Triggers keep the FTS index in sync with the main table automatically.
|
|
105
|
+
|
|
106
|
+
### 1.4 Running the Indexer
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Incremental index (only changed files since last run)
|
|
110
|
+
python3 scripts/rag-indexer.py
|
|
111
|
+
|
|
112
|
+
# Full re-index (drop and rebuild everything)
|
|
113
|
+
python3 scripts/rag-indexer.py --full
|
|
114
|
+
|
|
115
|
+
# Show index statistics
|
|
116
|
+
python3 scripts/rag-indexer.py --stats
|
|
117
|
+
|
|
118
|
+
# Custom database path
|
|
119
|
+
python3 scripts/rag-indexer.py --db /path/to/custom.db
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 1.5 Incremental Indexing
|
|
123
|
+
|
|
124
|
+
The indexer tracks file modification times in `state/rag/index-state.json`. On each run, it only re-indexes files that have changed since the last run. A `--full` flag forces a complete rebuild.
|
|
125
|
+
|
|
126
|
+
### 1.6 Performance
|
|
127
|
+
|
|
128
|
+
- WAL mode enabled (`PRAGMA journal_mode=WAL`) for concurrent read/write
|
|
129
|
+
- Synchronous mode set to NORMAL for faster writes
|
|
130
|
+
- Typical index time: < 5 seconds for incremental, < 30 seconds for full rebuild on ~10K documents
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 2. User Context Search (`user-context-search.py`)
|
|
135
|
+
|
|
136
|
+
Ring-fenced search that respects user access levels.
|
|
137
|
+
|
|
138
|
+
### 2.1 How It Works
|
|
139
|
+
|
|
140
|
+
1. Looks up the user in `config/caller-id-map.yaml` to determine access level
|
|
141
|
+
2. Maps access level to searchable paths/scopes
|
|
142
|
+
3. Executes search using one of two backends:
|
|
143
|
+
- **grep** (default): File-based grep with scoped directory paths
|
|
144
|
+
- **sqlite**: FTS5 query against the pre-indexed database
|
|
145
|
+
|
|
146
|
+
### 2.2 Usage
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Search as CEO (full access)
|
|
150
|
+
python3 scripts/user-context-search.py --user mehran --query "DFSA submission"
|
|
151
|
+
|
|
152
|
+
# Search as leadership (scoped access)
|
|
153
|
+
python3 scripts/user-context-search.py --user hootan --query "portal" --max-results 5
|
|
154
|
+
|
|
155
|
+
# Search as unknown user (public only)
|
|
156
|
+
python3 scripts/user-context-search.py --user unknown --query "adaptic"
|
|
157
|
+
|
|
158
|
+
# Use SQLite FTS5 backend
|
|
159
|
+
python3 scripts/user-context-search.py --user mehran --query "flight" --backend sqlite
|
|
160
|
+
|
|
161
|
+
# Text output format (vs JSON default)
|
|
162
|
+
python3 scripts/user-context-search.py --user mehran --query "test" --format text
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2.3 Access Level → Searchable Paths
|
|
166
|
+
|
|
167
|
+
| Access Level | Directories Searched |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `ceo` | Everything: `memory/`, `knowledge/`, `state/`, `outputs/`, `docs/`, `logs/` |
|
|
170
|
+
| `leadership` | `knowledge/` (company), `docs/`, research/briefs, own interaction logs |
|
|
171
|
+
| `partner` | `knowledge/sources/` (public), research, own interaction logs |
|
|
172
|
+
| `default` | `knowledge/sources/` only |
|
|
173
|
+
|
|
174
|
+
### 2.4 User Resolution
|
|
175
|
+
|
|
176
|
+
Users can be identified by:
|
|
177
|
+
- Username slug (e.g. `mehran`)
|
|
178
|
+
- Slack ID (e.g. `U099N1JGKRQ`)
|
|
179
|
+
- Email address (e.g. `mehran@adaptic.ai`)
|
|
180
|
+
- Phone number (e.g. `+971585291799`)
|
|
181
|
+
|
|
182
|
+
All resolve to the same user entry in `caller-id-map.yaml`.
|
|
183
|
+
|
|
184
|
+
### 2.5 No External Dependencies
|
|
185
|
+
|
|
186
|
+
The search script uses only Python standard library. PyYAML is used if available (faster), but a built-in YAML parser handles the `caller-id-map.yaml` structure if PyYAML is missing.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 3. Pre-Draft Context (`pre-draft-context.py`)
|
|
191
|
+
|
|
192
|
+
Retrieves relevant context about a recipient **before** composing a message. This is the core of the "know before you write" principle.
|
|
193
|
+
|
|
194
|
+
### 3.1 What It Retrieves
|
|
195
|
+
|
|
196
|
+
1. **Entity index lookup** — Finds the recipient in `memory/indexes/entity-relationships.yaml`
|
|
197
|
+
2. **User profile** — Loads `memory/profiles/users/{slug}.yaml` for standing instructions, preferences, tone
|
|
198
|
+
3. **Recent interactions** — Checks `memory/interactions/` for recent conversation history
|
|
199
|
+
4. **Queue context** — Checks `state/queues/` for related open items
|
|
200
|
+
5. **Disclosure boundaries** — Generates per-recipient information boundaries
|
|
201
|
+
|
|
202
|
+
### 3.2 Usage
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Full JSON context
|
|
206
|
+
python3 scripts/pre-draft-context.py --recipient "Graham Syder"
|
|
207
|
+
|
|
208
|
+
# With topic focus
|
|
209
|
+
python3 scripts/pre-draft-context.py --recipient "Hootan" --topic "DFSA compliance"
|
|
210
|
+
|
|
211
|
+
# Brief format (3-5 lines, suitable for prompt injection)
|
|
212
|
+
python3 scripts/pre-draft-context.py --recipient "Nima" --topic "83b election" --format brief
|
|
213
|
+
|
|
214
|
+
# By email address
|
|
215
|
+
python3 scripts/pre-draft-context.py --recipient "hootan@adaptic.ai" --format brief
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 3.3 Performance
|
|
219
|
+
|
|
220
|
+
Target: **< 500ms** per lookup. Achieves this by:
|
|
221
|
+
- File reads only (no API calls)
|
|
222
|
+
- JSON cache of entity index (`.entity-relationships.json` alongside the YAML)
|
|
223
|
+
- PyYAML C loader when available (10x faster than pure Python)
|
|
224
|
+
|
|
225
|
+
### 3.4 Exit Codes
|
|
226
|
+
|
|
227
|
+
| Code | Meaning |
|
|
228
|
+
|---|---|
|
|
229
|
+
| 0 | Context found |
|
|
230
|
+
| 1 | Recipient not found |
|
|
231
|
+
| 2 | Error |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 4. Pre-Draft Lookup Wrapper (`pre_draft_lookup.py`)
|
|
236
|
+
|
|
237
|
+
Thin wrapper around `pre-draft-context.py` designed for import into send scripts.
|
|
238
|
+
|
|
239
|
+
### 4.1 What It Adds
|
|
240
|
+
|
|
241
|
+
1. Calls `retrieve_context()` from `pre-draft-context.py`
|
|
242
|
+
2. Generates disclosure boundaries for the recipient (via `disclosure_boundaries.py`)
|
|
243
|
+
3. Logs the lookup result to `logs/audit/YYYY-MM-DD-pre-draft-lookups.jsonl`
|
|
244
|
+
4. Returns context dict or `None` — **never blocks a send**
|
|
245
|
+
|
|
246
|
+
### 4.2 Python Import
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
from pre_draft_lookup import pre_draft_lookup
|
|
250
|
+
|
|
251
|
+
context = pre_draft_lookup("Mehran Granfar", message_type="slack")
|
|
252
|
+
if context:
|
|
253
|
+
# context contains entity info, user profile, recent interactions
|
|
254
|
+
pass
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 4.3 CLI Usage (for Shell Scripts)
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
python3 scripts/pre_draft_lookup.py --recipient "Mehran Granfar" --type slack --channel C099ABC
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 4.4 Integration Points
|
|
264
|
+
|
|
265
|
+
Called automatically by these send scripts:
|
|
266
|
+
- `send-email-threaded.py` — imported as Python module
|
|
267
|
+
- `send-email-with-attachment.py` — imported as Python module
|
|
268
|
+
- `slack-send.sh` — called as subprocess before sending
|
|
269
|
+
- `send-whatsapp.sh` — called via `validate-outbound.py` pipeline
|
|
270
|
+
|
|
271
|
+
The lookup is **advisory only** — it enriches the agent's context but never prevents a send.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 5. Post-Interaction Indexer (`post-interaction-indexer.py`)
|
|
276
|
+
|
|
277
|
+
Automatically extracts entities, relationships, and facts from interactions and updates the entity index.
|
|
278
|
+
|
|
279
|
+
### 5.1 What It Extracts
|
|
280
|
+
|
|
281
|
+
From each interaction (email, Slack message, call transcript):
|
|
282
|
+
- **People** mentioned (names, titles, roles)
|
|
283
|
+
- **Organisations** referenced
|
|
284
|
+
- **Topics** discussed
|
|
285
|
+
- **Facts** stated (dates, decisions, commitments)
|
|
286
|
+
- **Relationships** between entities
|
|
287
|
+
|
|
288
|
+
### 5.2 When It Runs
|
|
289
|
+
|
|
290
|
+
| Trigger | How |
|
|
291
|
+
|---|---|
|
|
292
|
+
| Session end | `session-end-log.sh` hook spawns it in background with `--scan-today` |
|
|
293
|
+
| After inbox processing | Inbox processor calls it per-item |
|
|
294
|
+
| After backlog execution | Backlog executor calls it for interaction-heavy tasks |
|
|
295
|
+
| Manual backfill | Run with `--input` for specific files |
|
|
296
|
+
|
|
297
|
+
### 5.3 Usage
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Process a specific inbox item
|
|
301
|
+
python3 scripts/post-interaction-indexer.py --input state/inbox/slack/1775230363.978999-dm.json
|
|
302
|
+
|
|
303
|
+
# Process all unprocessed interactions from today
|
|
304
|
+
python3 scripts/post-interaction-indexer.py --scan-today
|
|
305
|
+
|
|
306
|
+
# Dry run (show extractions without writing)
|
|
307
|
+
python3 scripts/post-interaction-indexer.py --input <file> --dry-run
|
|
308
|
+
|
|
309
|
+
# Process from stdin
|
|
310
|
+
echo '{"event_type":"email","email":{"from":"Jane <jane@co.com>"}}' | \
|
|
311
|
+
python3 scripts/post-interaction-indexer.py --stdin
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 5.4 Output
|
|
315
|
+
|
|
316
|
+
Updates `memory/indexes/entity-relationships.yaml` with new entities and relationships. Uses a JSON cache (`.entity-relationships.json`) for fast reads.
|
|
317
|
+
|
|
318
|
+
### 5.5 Performance Target
|
|
319
|
+
|
|
320
|
+
< 2 seconds per interaction (regex-based extraction, no API calls).
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 6. Directory Structure
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
state/rag/
|
|
328
|
+
search.db # SQLite FTS5 database
|
|
329
|
+
index-state.json # File modification tracking for incremental indexing
|
|
330
|
+
|
|
331
|
+
memory/
|
|
332
|
+
interactions/ # Raw interaction logs (JSONL)
|
|
333
|
+
slack/
|
|
334
|
+
{channel}/{date}.jsonl
|
|
335
|
+
email/
|
|
336
|
+
{user}/{date}.jsonl
|
|
337
|
+
indexes/
|
|
338
|
+
entity-relationships.yaml # Extracted entities and relationships
|
|
339
|
+
.entity-relationships.json # JSON cache for fast reads
|
|
340
|
+
profiles/
|
|
341
|
+
users/{slug}.yaml # Per-user preferences, standing instructions
|
|
342
|
+
channels/{name}.yaml # Per-channel tone, rules
|
|
343
|
+
|
|
344
|
+
knowledge/
|
|
345
|
+
sources/ # Public company knowledge (yaml)
|
|
346
|
+
decisions/ # Strategic decisions (leadership+)
|
|
347
|
+
syntheses/ # Analysis summaries
|
|
348
|
+
|
|
349
|
+
config/
|
|
350
|
+
caller-id-map.yaml # User → access level mapping
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 7. Testing
|
|
356
|
+
|
|
357
|
+
### 7.1 RAG Search Tests
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# Run the full RAG search test suite
|
|
361
|
+
./scripts/test-rag-search.sh
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Tests:
|
|
365
|
+
1. CEO (mehran) gets broad results
|
|
366
|
+
2. Leadership (hootan) gets scoped results (no private CEO data)
|
|
367
|
+
3. Unknown user gets minimal access (knowledge/sources only)
|
|
368
|
+
4. Slack ID resolution works
|
|
369
|
+
5. Email resolution works
|
|
370
|
+
|
|
371
|
+
### 7.2 Pre-Draft Integration Test
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
python3 scripts/test-pre-draft-integration.py
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### 7.3 Manual Verification
|
|
378
|
+
|
|
379
|
+
| # | Test | How to Verify |
|
|
380
|
+
|---|---|---|
|
|
381
|
+
| 1 | Index builds | `python3 scripts/rag-indexer.py --stats` — should show document counts |
|
|
382
|
+
| 2 | Incremental works | Run indexer twice; second run should skip unchanged files |
|
|
383
|
+
| 3 | Full rebuild | `python3 scripts/rag-indexer.py --full` — should recreate DB |
|
|
384
|
+
| 4 | CEO search | `python3 scripts/user-context-search.py --user mehran --query "test"` |
|
|
385
|
+
| 5 | Scoped search | Leadership user shouldn't see CEO-only docs |
|
|
386
|
+
| 6 | Pre-draft context | `python3 scripts/pre-draft-context.py --recipient "Mehran"` |
|
|
387
|
+
| 7 | Lookup wrapper | `python3 scripts/pre_draft_lookup.py --recipient "Mehran" --type slack` |
|
|
388
|
+
| 8 | Post-interaction | `python3 scripts/post-interaction-indexer.py --scan-today` |
|
|
389
|
+
| 9 | Audit logging | Check `logs/audit/YYYY-MM-DD-pre-draft-lookups.jsonl` |
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 8. Troubleshooting
|
|
394
|
+
|
|
395
|
+
### "No results found" for a query you know exists
|
|
396
|
+
|
|
397
|
+
1. Check the index is built: `python3 scripts/rag-indexer.py --stats`
|
|
398
|
+
2. If stats show 0 documents, run a full index: `python3 scripts/rag-indexer.py --full`
|
|
399
|
+
3. Check the content is in an indexed directory (see section 1.1)
|
|
400
|
+
4. Try the grep backend: `--backend grep` may find files not yet indexed
|
|
401
|
+
|
|
402
|
+
### Recipient not found in pre-draft context
|
|
403
|
+
|
|
404
|
+
1. Check entity index exists: `ls memory/indexes/entity-relationships.yaml`
|
|
405
|
+
2. Run the post-interaction indexer: `python3 scripts/post-interaction-indexer.py --scan-today`
|
|
406
|
+
3. Check if the recipient has a user profile: `ls memory/profiles/users/`
|
|
407
|
+
4. Names must match — try variations (full name, email, slug)
|
|
408
|
+
|
|
409
|
+
### Search too slow
|
|
410
|
+
|
|
411
|
+
1. Use the sqlite backend instead of grep: `--backend sqlite`
|
|
412
|
+
2. Rebuild the FTS index: `python3 scripts/rag-indexer.py --full`
|
|
413
|
+
3. Check DB size: `ls -lh state/rag/search.db`
|
|
414
|
+
|
|
415
|
+
### PyYAML not available
|
|
416
|
+
|
|
417
|
+
The search script works without PyYAML using a built-in minimal parser. However, the post-interaction indexer **requires** PyYAML:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
pip3 install pyyaml
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Index state corrupted
|
|
424
|
+
|
|
425
|
+
Delete and rebuild:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
rm state/rag/index-state.json
|
|
429
|
+
python3 scripts/rag-indexer.py --full
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Key Files
|
|
435
|
+
|
|
436
|
+
| File | Purpose |
|
|
437
|
+
|---|---|
|
|
438
|
+
| `scripts/rag-indexer.py` | SQLite FTS5 indexer (incremental + full rebuild) |
|
|
439
|
+
| `scripts/user-context-search.py` | Per-user ring-fenced search (grep or sqlite) |
|
|
440
|
+
| `scripts/pre-draft-context.py` | Pre-send recipient context retrieval |
|
|
441
|
+
| `scripts/pre_draft_lookup.py` | Wrapper for send script integration + audit logging |
|
|
442
|
+
| `scripts/post-interaction-indexer.py` | Entity/relationship extraction from interactions |
|
|
443
|
+
| `scripts/test-rag-search.sh` | RAG search test suite |
|
|
444
|
+
| `scripts/test-rag-phase2.sh` | Phase 2 (FTS5) test suite |
|
|
445
|
+
| `scripts/test-pre-draft-integration.py` | Pre-draft integration tests |
|
|
446
|
+
| `config/caller-id-map.yaml` | User → access level mapping |
|
|
447
|
+
| `state/rag/search.db` | SQLite FTS5 database |
|
|
448
|
+
| `state/rag/index-state.json` | Incremental indexing state |
|
|
449
|
+
| `memory/indexes/entity-relationships.yaml` | Extracted entity index |
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Related Documents
|
|
454
|
+
|
|
455
|
+
- [Outbound Governance Setup](outbound-governance-setup.md) — How pre-draft context feeds into disclosure assessment
|
|
456
|
+
- [Email Setup](email-setup.md) — Email send scripts that consume pre-draft context
|
|
457
|
+
- [Slack Setup](slack-setup.md) — Slack send script pre-draft integration
|
|
458
|
+
- [Voice & SMS Setup](voice-sms-setup.md) — Caller ID mapping shared with RAG access control
|
|
459
|
+
- [Poller & Daemon Setup](poller-daemon-setup.md) — Session-end hook triggers post-interaction indexer
|