@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,438 @@
|
|
|
1
|
+
# Outbound Governance Setup Guide
|
|
2
|
+
|
|
3
|
+
How the agent's outbound communication safety system works: pre-send audit hooks, factual validation, outbound deduplication (atomic locks + LLM semantic checks), information barriers, disclosure assessment, and audit logging. This is the governance layer that ensures every outbound message is safe, accurate, and non-duplicated.
|
|
4
|
+
|
|
5
|
+
**Prerequisites**: At least one communication channel configured ([Email](email-setup.md), [Slack](slack-setup.md), [WhatsApp](whatsapp-setup.md), or [SMS](voice-sms-setup.md)).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Architecture Overview
|
|
10
|
+
|
|
11
|
+
Every outbound message passes through multiple safety layers before being sent:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
15
|
+
│ Agent drafts a message │
|
|
16
|
+
│ │ │
|
|
17
|
+
│ ▼ │
|
|
18
|
+
│ ┌─── Layer 0: Factual Validation ──────────────────────────┐ │
|
|
19
|
+
│ │ validate-outbound.py / validate_outbound.py │ │
|
|
20
|
+
│ │ Checks: relationship accuracy, AI disclosure, scheduling │ │
|
|
21
|
+
│ │ Result: PASS / WARN / BLOCK │ │
|
|
22
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
23
|
+
│ │ │
|
|
24
|
+
│ ▼ │
|
|
25
|
+
│ ┌─── Layer 1: LLM Semantic Dedup (email only) ─────────────┐ │
|
|
26
|
+
│ │ llm_email_dedup.py │ │
|
|
27
|
+
│ │ Asks Claude Haiku: "Was this topic already addressed?" │ │
|
|
28
|
+
│ │ Result: PASS / DEDUP_SKIP │ │
|
|
29
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
30
|
+
│ │ │
|
|
31
|
+
│ ▼ │
|
|
32
|
+
│ ┌─── Layer 2: Information Barrier Check ────────────────────┐ │
|
|
33
|
+
│ │ disclosure_assessment.py + disclosure_boundaries.py │ │
|
|
34
|
+
│ │ Checks: recipient access level, content provenance │ │
|
|
35
|
+
│ │ Result: PASS / WARN / STRIP / BLOCK │ │
|
|
36
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
37
|
+
│ │ │
|
|
38
|
+
│ ▼ │
|
|
39
|
+
│ ┌─── Layer 3: Content-Hash Dedup ──────────────────────────┐ │
|
|
40
|
+
│ │ outbound-dedup.sh / outbound_dedup.py │ │
|
|
41
|
+
│ │ Atomic mkdir lock: sha256(to + subject + body[:100]) │ │
|
|
42
|
+
│ │ Result: CLAIMED (send) / DEDUP_SKIP (another session) │ │
|
|
43
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
44
|
+
│ │ │
|
|
45
|
+
│ ▼ │
|
|
46
|
+
│ ┌─── Layer 4: Pre-Send Audit Hook ─────────────────────────┐ │
|
|
47
|
+
│ │ hooks/pre-send-audit.sh │ │
|
|
48
|
+
│ │ Rate limits: 3,000/hour, 20,000/day │ │
|
|
49
|
+
│ │ Result: ALLOWED / BLOCKED │ │
|
|
50
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
51
|
+
│ │ │
|
|
52
|
+
│ ▼ │
|
|
53
|
+
│ SEND ──▶ Post-action log (hooks/post-action-log.sh) │
|
|
54
|
+
│ Session end log (hooks/session-end-log.sh) │
|
|
55
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Design principle**: Fail-open on infrastructure errors. If a dedup lock fails or a validation script crashes, the message sends anyway. It's better to send a duplicate than to silently drop a message.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 1. Claude Code Hooks (`scripts/hooks/`)
|
|
63
|
+
|
|
64
|
+
Hooks are shell scripts registered in `.claude/settings.json` that execute before or after tool calls.
|
|
65
|
+
|
|
66
|
+
### 1.1 Pre-Send Audit (`pre-send-audit.sh`)
|
|
67
|
+
|
|
68
|
+
**Trigger**: `PreToolUse` hook, fires before Slack/Gmail send tools.
|
|
69
|
+
|
|
70
|
+
**What it does**:
|
|
71
|
+
1. Reads the tool input from stdin
|
|
72
|
+
2. Checks daily send counter against rate limits (3,000/hour, 20,000/day)
|
|
73
|
+
3. Logs the send to `logs/audit/YYYY-MM-DD-sends.jsonl`
|
|
74
|
+
4. Exit 0 = allowed (message shown to Claude)
|
|
75
|
+
5. Exit 2 = blocked (rejection message shown to Claude)
|
|
76
|
+
|
|
77
|
+
**Rate limit state**: `logs/audit/send-counter.yaml` — tracks hourly and daily totals, resets at midnight.
|
|
78
|
+
|
|
79
|
+
### 1.2 Post-Action Log (`post-action-log.sh`)
|
|
80
|
+
|
|
81
|
+
**Trigger**: `PostToolUse` hook, fires after every tool execution.
|
|
82
|
+
|
|
83
|
+
**What it does**:
|
|
84
|
+
- Logs tool name and completion timestamp to `logs/audit/YYYY-MM-DD-actions.jsonl`
|
|
85
|
+
- Consumes stdin (tool result) without blocking
|
|
86
|
+
|
|
87
|
+
### 1.3 MCP Slack Send Block (`block-mcp-slack-send.sh`)
|
|
88
|
+
|
|
89
|
+
**Trigger**: `PreToolUse` hook, matches MCP Slack send tools.
|
|
90
|
+
|
|
91
|
+
**What it does**:
|
|
92
|
+
- Unconditionally blocks MCP Slack sends (exit 2)
|
|
93
|
+
- Enforces CEO directive: all Slack sends must use `scripts/slack-send.sh` with User OAuth Token
|
|
94
|
+
- MCP Slack adds "Sent using @Claude" label, breaking agent identity
|
|
95
|
+
|
|
96
|
+
### 1.4 Session End Log (`session-end-log.sh`)
|
|
97
|
+
|
|
98
|
+
**Trigger**: `Stop` hook, fires when a Claude session ends.
|
|
99
|
+
|
|
100
|
+
**What it does**:
|
|
101
|
+
1. Logs session completion to `logs/sessions/YYYY-MM-DD-sessions.jsonl`
|
|
102
|
+
2. Spawns the post-interaction indexer in the background (`post-interaction-indexer.py --scan-today`)
|
|
103
|
+
3. Fire-and-forget: indexer runs asynchronously, doesn't block session teardown
|
|
104
|
+
|
|
105
|
+
### 1.5 Hook Registration
|
|
106
|
+
|
|
107
|
+
Hooks are registered in `.claude/settings.json`:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"hooks": {
|
|
112
|
+
"PreToolUse": [
|
|
113
|
+
{
|
|
114
|
+
"matcher": "mcp__claude_ai_Slack__slack_send_message",
|
|
115
|
+
"command": "bash scripts/hooks/block-mcp-slack-send.sh"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"matcher": "Bash",
|
|
119
|
+
"command": "bash scripts/hooks/pre-send-audit.sh slack"
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"PostToolUse": [
|
|
123
|
+
{
|
|
124
|
+
"matcher": "*",
|
|
125
|
+
"command": "bash scripts/hooks/post-action-log.sh"
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"Stop": [
|
|
129
|
+
{
|
|
130
|
+
"command": "bash scripts/hooks/session-end-log.sh"
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 2. Factual Validation (`validate-outbound.py`)
|
|
140
|
+
|
|
141
|
+
Checks outbound messages for factual errors before sending.
|
|
142
|
+
|
|
143
|
+
### 2.1 What It Checks
|
|
144
|
+
|
|
145
|
+
| Check | Severity | Example |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| Relationship claims | Block | Claiming a meeting happened that didn't |
|
|
148
|
+
| AI disclosure | Block | Revealing the agent is AI in external comms |
|
|
149
|
+
| In-person scheduling | Block | Scheduling the agent for a physical meeting |
|
|
150
|
+
| Title accuracy | Warn | Using wrong title for a contact |
|
|
151
|
+
| Date accuracy | Warn | Referencing incorrect dates |
|
|
152
|
+
|
|
153
|
+
### 2.2 Usage
|
|
154
|
+
|
|
155
|
+
Called automatically by send scripts, or manually:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
echo "Let's meet at the office tomorrow" | python3 scripts/validate-outbound.py --type slack --recipient "C1234567890"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Exit codes**:
|
|
162
|
+
- 0: passed (safe to send)
|
|
163
|
+
- 1: issues found (check JSON output for blockers vs warnings)
|
|
164
|
+
|
|
165
|
+
### 2.3 Integration
|
|
166
|
+
|
|
167
|
+
Every send script calls `validate-outbound.py` in its pre-send pipeline. If the validator finds `block`-severity issues, the send is aborted with an error message explaining what to fix.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 3. Outbound Deduplication
|
|
172
|
+
|
|
173
|
+
### 3.1 Content-Hash Dedup (`outbound-dedup.sh`)
|
|
174
|
+
|
|
175
|
+
Prevents concurrent Claude sessions from sending identical messages.
|
|
176
|
+
|
|
177
|
+
**Mechanism**: Atomic `mkdir`-based locking (POSIX-guaranteed atomic).
|
|
178
|
+
|
|
179
|
+
**Key generation**:
|
|
180
|
+
|
|
181
|
+
| Channel | Hash Input |
|
|
182
|
+
|---|---|
|
|
183
|
+
| Email | `sha256(to + subject + body[:100])` |
|
|
184
|
+
| SMS | `sha256(to + body[:100])` |
|
|
185
|
+
| WhatsApp | `sha256(to + body[:100])` |
|
|
186
|
+
| Slack | Channel + message_ts (passthrough) |
|
|
187
|
+
|
|
188
|
+
**Commands**:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Generate a dedup key
|
|
192
|
+
./scripts/outbound-dedup.sh generate-key email "to@example.com" "Subject" "Body text"
|
|
193
|
+
|
|
194
|
+
# Acquire a lock (returns CLAIMED or DEDUP_SKIP)
|
|
195
|
+
./scripts/outbound-dedup.sh acquire email <key> <session_id>
|
|
196
|
+
|
|
197
|
+
# Confirm send succeeded (audit trail)
|
|
198
|
+
./scripts/outbound-dedup.sh confirm email <key> "preview text"
|
|
199
|
+
|
|
200
|
+
# Check lock status
|
|
201
|
+
./scripts/outbound-dedup.sh check email <key>
|
|
202
|
+
|
|
203
|
+
# Clean up expired locks
|
|
204
|
+
./scripts/outbound-dedup.sh cleanup [max_age_minutes]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Lock TTL**: 720 minutes (12 hours) — long because email dedup needs to span multiple sessions.
|
|
208
|
+
|
|
209
|
+
**Lock directory**: `state/locks/outbound/{channel}/{dedup-key}/`
|
|
210
|
+
|
|
211
|
+
### 3.2 Slack Response Dedup (`slack-responded.sh`)
|
|
212
|
+
|
|
213
|
+
Specialised dedup for Slack responses. Uses the same atomic mkdir pattern but keyed by `channel + message_ts`:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Acquire response lock
|
|
217
|
+
./scripts/slack-responded.sh acquire <channel> <message_ts> <session_id>
|
|
218
|
+
|
|
219
|
+
# Confirm response sent
|
|
220
|
+
./scripts/slack-responded.sh confirm <channel> <message_ts> "preview text"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 3.3 LLM Semantic Dedup (`llm_email_dedup.py`)
|
|
224
|
+
|
|
225
|
+
For email only. Uses Claude Haiku to check if a topic has already been addressed:
|
|
226
|
+
|
|
227
|
+
1. Fetches recent sent emails to the same recipient via IMAP
|
|
228
|
+
2. Sends both the draft and recent emails to Haiku with the question: "Has this specific topic already been addressed in a recent email?"
|
|
229
|
+
3. Returns `DEDUP_SKIP` if the LLM says yes
|
|
230
|
+
|
|
231
|
+
This catches cases where the content-hash doesn't match (different wording, same topic).
|
|
232
|
+
|
|
233
|
+
### 3.4 Cleanup
|
|
234
|
+
|
|
235
|
+
Stale locks are cleaned by:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Clean locks older than 5 minutes (default)
|
|
239
|
+
./scripts/outbound-dedup.sh cleanup
|
|
240
|
+
|
|
241
|
+
# Clean locks older than 60 minutes
|
|
242
|
+
./scripts/outbound-dedup.sh cleanup 60
|
|
243
|
+
|
|
244
|
+
# Bulk cleanup script
|
|
245
|
+
./scripts/outbound-dedup-cleanup.sh
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 4. Information Barriers & Disclosure Assessment
|
|
251
|
+
|
|
252
|
+
### 4.1 Disclosure Assessment (`disclosure_assessment.py`)
|
|
253
|
+
|
|
254
|
+
The hard gate that prevents information leakage across recipient boundaries.
|
|
255
|
+
|
|
256
|
+
**What it does**:
|
|
257
|
+
1. Loads the recipient's user profile from `memory/profiles/users/`
|
|
258
|
+
2. Loads the channel profile from `memory/profiles/channels/` (if Slack)
|
|
259
|
+
3. Extracts keywords and entities from the draft message
|
|
260
|
+
4. Checks message content against the recipient's information boundaries
|
|
261
|
+
5. Checks content provenance (where the information originated)
|
|
262
|
+
6. Assigns severity: low (warn), medium (strip), high (block), critical (block + escalate)
|
|
263
|
+
|
|
264
|
+
**Exit codes**:
|
|
265
|
+
- 0: passed or warn (safe to send)
|
|
266
|
+
- 1: stripped (send but redact flagged content)
|
|
267
|
+
- 2: blocked (do not send)
|
|
268
|
+
|
|
269
|
+
**Usage**:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Check a message before sending
|
|
273
|
+
echo "The JVA negotiation is progressing well" | \
|
|
274
|
+
python3 scripts/disclosure_assessment.py --recipient shayan-kargarian
|
|
275
|
+
|
|
276
|
+
# With channel context
|
|
277
|
+
python3 scripts/disclosure_assessment.py \
|
|
278
|
+
--recipient shayan-kargarian --channel rollup-strategy \
|
|
279
|
+
--message "The acquisition target has confirmed AED 40K"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 4.2 Disclosure Boundaries (`disclosure_boundaries.py`)
|
|
283
|
+
|
|
284
|
+
Defines the information boundary rules:
|
|
285
|
+
|
|
286
|
+
- What information each recipient can receive
|
|
287
|
+
- What topics are restricted per relationship type
|
|
288
|
+
- What sources/matters are confidential to specific deal teams
|
|
289
|
+
|
|
290
|
+
Rules are derived from user profiles and the information barriers policy.
|
|
291
|
+
|
|
292
|
+
### 4.3 Information Barriers Policy
|
|
293
|
+
|
|
294
|
+
Defined in `policies/information-barriers.yaml` (if present). Specifies:
|
|
295
|
+
|
|
296
|
+
- **Chinese walls** between deal teams
|
|
297
|
+
- **Restricted topics** per recipient classification
|
|
298
|
+
- **Provenance tracking** — which information came from which source/matter
|
|
299
|
+
- **Escalation rules** — what happens when a barrier is breached
|
|
300
|
+
|
|
301
|
+
### 4.4 Testing Information Barriers
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
python3 scripts/test-information-barriers.py
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Runs test scenarios to verify barriers are correctly enforced.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## 5. Audit Trail
|
|
312
|
+
|
|
313
|
+
### 5.1 Log Files
|
|
314
|
+
|
|
315
|
+
| Log | Path | Contents |
|
|
316
|
+
|---|---|---|
|
|
317
|
+
| Actions | `logs/audit/YYYY-MM-DD-actions.jsonl` | All tool executions, sends, dedup events |
|
|
318
|
+
| Sends | `logs/audit/YYYY-MM-DD-sends.jsonl` | Pre-send audit decisions (allowed/blocked) |
|
|
319
|
+
| Validation | `logs/audit/YYYY-MM-DD-validation.jsonl` | Factual validation results |
|
|
320
|
+
| Pre-draft | `logs/audit/YYYY-MM-DD-pre-draft-lookups.jsonl` | Context lookups before drafting |
|
|
321
|
+
| Sessions | `logs/sessions/YYYY-MM-DD-sessions.jsonl` | Session start/end events |
|
|
322
|
+
|
|
323
|
+
### 5.2 Rate Limit State
|
|
324
|
+
|
|
325
|
+
`logs/audit/send-counter.yaml`:
|
|
326
|
+
|
|
327
|
+
```yaml
|
|
328
|
+
date: "2026-04-09"
|
|
329
|
+
hourly: {}
|
|
330
|
+
totals:
|
|
331
|
+
slack: 42
|
|
332
|
+
gmail: 8
|
|
333
|
+
whatsapp: 3
|
|
334
|
+
total: 53
|
|
335
|
+
limits:
|
|
336
|
+
per_hour: 3000
|
|
337
|
+
per_day: 20000
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Resets daily at midnight.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## 6. Self-Optimization Metrics
|
|
345
|
+
|
|
346
|
+
`scripts/self-optimization/compute-metrics.py` calculates governance metrics:
|
|
347
|
+
|
|
348
|
+
- Dedup hit rate (what percentage of sends were caught as duplicates)
|
|
349
|
+
- Validation block rate (what percentage of messages had issues)
|
|
350
|
+
- Average response latency per channel
|
|
351
|
+
- Session concurrency utilisation
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 7. Testing
|
|
356
|
+
|
|
357
|
+
| # | Test | How to Verify |
|
|
358
|
+
|---|---|---|
|
|
359
|
+
| 1 | Pre-send hook | Send a Slack message — check `logs/audit/YYYY-MM-DD-sends.jsonl` |
|
|
360
|
+
| 2 | Rate limit | Manually set counter to 19999 in `send-counter.yaml` — next send should block |
|
|
361
|
+
| 3 | MCP block | Attempt MCP Slack send — should be blocked |
|
|
362
|
+
| 4 | Factual validation | Send message mentioning in-person meeting — should block |
|
|
363
|
+
| 5 | Content-hash dedup | Send identical email twice — second should `DEDUP_SKIP` |
|
|
364
|
+
| 6 | LLM dedup | Send two different emails about same topic — second should warn |
|
|
365
|
+
| 7 | Slack response dedup | Reply to same message from two sessions — one should skip |
|
|
366
|
+
| 8 | Disclosure assessment | Test with restricted content + external recipient |
|
|
367
|
+
| 9 | Audit logging | Verify all sends appear in `logs/audit/` |
|
|
368
|
+
| 10 | Lock cleanup | Run `./scripts/outbound-dedup.sh cleanup` — stale locks removed |
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 8. Troubleshooting
|
|
373
|
+
|
|
374
|
+
### All sends blocked: "Daily send limit reached"
|
|
375
|
+
|
|
376
|
+
1. Check `logs/audit/send-counter.yaml` — if total is at 20,000, wait for midnight reset
|
|
377
|
+
2. For emergencies, manually reset the counter: delete the file (it recreates on next send)
|
|
378
|
+
3. Consider if a runaway session is sending in a loop
|
|
379
|
+
|
|
380
|
+
### Dedup false positives (legitimate messages being skipped)
|
|
381
|
+
|
|
382
|
+
1. Check lock directory: `ls state/locks/outbound/email/`
|
|
383
|
+
2. Clean stale locks: `./scripts/outbound-dedup.sh cleanup 5`
|
|
384
|
+
3. For email: reduce lock TTL if 12 hours is too long for your use case
|
|
385
|
+
4. Use `--force` flag on send scripts to bypass dedup for exceptional cases
|
|
386
|
+
|
|
387
|
+
### Disclosure assessment blocking legitimate messages
|
|
388
|
+
|
|
389
|
+
1. Check the recipient's user profile in `memory/profiles/users/`
|
|
390
|
+
2. Review what information boundaries are set
|
|
391
|
+
3. Run the assessment manually to see the exact output
|
|
392
|
+
4. Update the user profile if boundaries are too restrictive
|
|
393
|
+
|
|
394
|
+
### Hooks not firing
|
|
395
|
+
|
|
396
|
+
1. Check `.claude/settings.json` has the hooks registered
|
|
397
|
+
2. Verify hook scripts are executable: `chmod +x scripts/hooks/*.sh`
|
|
398
|
+
3. Check hook script paths are correct (relative to repo root)
|
|
399
|
+
4. Test hook manually: `echo '{}' | bash scripts/hooks/pre-send-audit.sh slack`
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Key Files
|
|
404
|
+
|
|
405
|
+
| File | Purpose |
|
|
406
|
+
|---|---|
|
|
407
|
+
| **Hooks** | |
|
|
408
|
+
| `scripts/hooks/pre-send-audit.sh` | Rate limiting and send logging |
|
|
409
|
+
| `scripts/hooks/post-action-log.sh` | Tool completion logging |
|
|
410
|
+
| `scripts/hooks/block-mcp-slack-send.sh` | MCP Slack send block |
|
|
411
|
+
| `scripts/hooks/session-end-log.sh` | Session end logging + indexer trigger |
|
|
412
|
+
| **Validation** | |
|
|
413
|
+
| `scripts/validate-outbound.py` | Factual validation (relationship, dates, disclosure) |
|
|
414
|
+
| `scripts/validate_outbound.py` | Alternate import path for Python scripts |
|
|
415
|
+
| **Dedup** | |
|
|
416
|
+
| `scripts/outbound-dedup.sh` | Atomic content-hash deduplication |
|
|
417
|
+
| `scripts/outbound_dedup.py` | Python dedup module (imported by send scripts) |
|
|
418
|
+
| `scripts/outbound-dedup-cleanup.sh` | Stale lock cleanup |
|
|
419
|
+
| `scripts/slack-responded.sh` | Slack response deduplication |
|
|
420
|
+
| `scripts/llm_email_dedup.py` | LLM semantic email deduplication |
|
|
421
|
+
| **Information Barriers** | |
|
|
422
|
+
| `scripts/disclosure_assessment.py` | Post-draft disclosure analysis |
|
|
423
|
+
| `scripts/disclosure_boundaries.py` | Information boundary rule definitions |
|
|
424
|
+
| `scripts/test-information-barriers.py` | Barrier test suite |
|
|
425
|
+
| **Policy** | |
|
|
426
|
+
| `policies/action-classification.yaml` | Action risk levels and approval rules |
|
|
427
|
+
| `policies/information-barriers.yaml` | Information barrier definitions |
|
|
428
|
+
| `.claude/settings.json` | Hook registration |
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Related Documents
|
|
433
|
+
|
|
434
|
+
- [Email Setup](email-setup.md) — Email dedup pipeline integration
|
|
435
|
+
- [Slack Setup](slack-setup.md) — Slack dedup and MCP block
|
|
436
|
+
- [Communications Policy](../governance/communications-policy.md) — Voice modes and approval rules
|
|
437
|
+
- [Action Approval Model](../governance/action-approval-model.md) — Approval workflows
|
|
438
|
+
- [Information Barrier Design](../superpowers/specs/2026-04-05-information-barrier-design.md) — Technical specification
|