@tekmidian/pai 0.3.2 → 0.5.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/ARCHITECTURE.md +16 -10
- package/README.md +46 -6
- package/dist/{auto-route-JjW3f7pV.mjs → auto-route-B5MSUJZK.mjs} +3 -3
- package/dist/{auto-route-JjW3f7pV.mjs.map → auto-route-B5MSUJZK.mjs.map} +1 -1
- package/dist/cli/index.mjs +313 -43
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{config-DELNqq3Z.mjs → config-B4brrHHE.mjs} +1 -1
- package/dist/{config-DELNqq3Z.mjs.map → config-B4brrHHE.mjs.map} +1 -1
- package/dist/daemon/index.mjs +7 -7
- package/dist/daemon-mcp/index.mjs +11 -4
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{daemon-CeTX4NpF.mjs → daemon-s868Paua.mjs} +12 -12
- package/dist/{daemon-CeTX4NpF.mjs.map → daemon-s868Paua.mjs.map} +1 -1
- package/dist/{detect-D7gPV3fQ.mjs → detect-CdaA48EI.mjs} +1 -1
- package/dist/{detect-D7gPV3fQ.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
- package/dist/{detector-cYYhK2Mi.mjs → detector-Bp-2SM3x.mjs} +2 -2
- package/dist/{detector-cYYhK2Mi.mjs.map → detector-Bp-2SM3x.mjs.map} +1 -1
- package/dist/{factory-DZLvRf4m.mjs → factory-CeXQzlwn.mjs} +3 -3
- package/dist/{factory-DZLvRf4m.mjs.map → factory-CeXQzlwn.mjs.map} +1 -1
- package/dist/hooks/capture-all-events.mjs +238 -0
- package/dist/hooks/capture-all-events.mjs.map +7 -0
- package/dist/hooks/capture-session-summary.mjs +198 -0
- package/dist/hooks/capture-session-summary.mjs.map +7 -0
- package/dist/hooks/capture-tool-output.mjs +105 -0
- package/dist/hooks/capture-tool-output.mjs.map +7 -0
- package/dist/hooks/cleanup-session-files.mjs +129 -0
- package/dist/hooks/cleanup-session-files.mjs.map +7 -0
- package/dist/hooks/context-compression-hook.mjs +283 -0
- package/dist/hooks/context-compression-hook.mjs.map +7 -0
- package/dist/hooks/initialize-session.mjs +206 -0
- package/dist/hooks/initialize-session.mjs.map +7 -0
- package/dist/hooks/load-core-context.mjs +110 -0
- package/dist/hooks/load-core-context.mjs.map +7 -0
- package/dist/hooks/load-project-context.mjs +548 -0
- package/dist/hooks/load-project-context.mjs.map +7 -0
- package/dist/hooks/security-validator.mjs +159 -0
- package/dist/hooks/security-validator.mjs.map +7 -0
- package/dist/hooks/stop-hook.mjs +625 -0
- package/dist/hooks/stop-hook.mjs.map +7 -0
- package/dist/hooks/subagent-stop-hook.mjs +152 -0
- package/dist/hooks/subagent-stop-hook.mjs.map +7 -0
- package/dist/hooks/sync-todo-to-md.mjs +322 -0
- package/dist/hooks/sync-todo-to-md.mjs.map +7 -0
- package/dist/hooks/update-tab-on-action.mjs +90 -0
- package/dist/hooks/update-tab-on-action.mjs.map +7 -0
- package/dist/hooks/update-tab-titles.mjs +55 -0
- package/dist/hooks/update-tab-titles.mjs.map +7 -0
- package/dist/index.d.mts +29 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -3
- package/dist/{indexer-backend-BHztlJJg.mjs → indexer-backend-DQO-FqAI.mjs} +1 -1
- package/dist/{indexer-backend-BHztlJJg.mjs.map → indexer-backend-DQO-FqAI.mjs.map} +1 -1
- package/dist/{ipc-client-CLt2fNlC.mjs → ipc-client-CgSpwHDC.mjs} +1 -1
- package/dist/{ipc-client-CLt2fNlC.mjs.map → ipc-client-CgSpwHDC.mjs.map} +1 -1
- package/dist/mcp/index.mjs +15 -5
- package/dist/mcp/index.mjs.map +1 -1
- package/dist/{postgres-CRBe30Ag.mjs → postgres-CIxeqf_n.mjs} +1 -1
- package/dist/{postgres-CRBe30Ag.mjs.map → postgres-CIxeqf_n.mjs.map} +1 -1
- package/dist/reranker-D7bRAHi6.mjs +71 -0
- package/dist/reranker-D7bRAHi6.mjs.map +1 -0
- package/dist/{schemas-BY3Pjvje.mjs → schemas-BFIgGntb.mjs} +1 -1
- package/dist/{schemas-BY3Pjvje.mjs.map → schemas-BFIgGntb.mjs.map} +1 -1
- package/dist/{search-GK0ibTJy.mjs → search-_oHfguA5.mjs} +47 -4
- package/dist/search-_oHfguA5.mjs.map +1 -0
- package/dist/{sqlite-RyR8Up1v.mjs → sqlite-CymLKiDE.mjs} +2 -2
- package/dist/{sqlite-RyR8Up1v.mjs.map → sqlite-CymLKiDE.mjs.map} +1 -1
- package/dist/{tools-CUg0Lyg-.mjs → tools-Dx7GjOHd.mjs} +23 -14
- package/dist/tools-Dx7GjOHd.mjs.map +1 -0
- package/dist/{vault-indexer-Bo2aPSzP.mjs → vault-indexer-DXWs9pDn.mjs} +1 -1
- package/dist/{vault-indexer-Bo2aPSzP.mjs.map → vault-indexer-DXWs9pDn.mjs.map} +1 -1
- package/dist/{zettelkasten-Co-w0XSZ.mjs → zettelkasten-e-a4rW_6.mjs} +2 -2
- package/dist/{zettelkasten-Co-w0XSZ.mjs.map → zettelkasten-e-a4rW_6.mjs.map} +1 -1
- package/package.json +4 -2
- package/scripts/build-hooks.mjs +51 -0
- package/src/hooks/ts/capture-all-events.ts +179 -0
- package/src/hooks/ts/lib/detect-environment.ts +53 -0
- package/src/hooks/ts/lib/metadata-extraction.ts +144 -0
- package/src/hooks/ts/lib/pai-paths.ts +124 -0
- package/src/hooks/ts/lib/project-utils.ts +914 -0
- package/src/hooks/ts/post-tool-use/capture-tool-output.ts +78 -0
- package/src/hooks/ts/post-tool-use/sync-todo-to-md.ts +230 -0
- package/src/hooks/ts/post-tool-use/update-tab-on-action.ts +145 -0
- package/src/hooks/ts/pre-compact/context-compression-hook.ts +155 -0
- package/src/hooks/ts/pre-tool-use/security-validator.ts +258 -0
- package/src/hooks/ts/session-end/capture-session-summary.ts +185 -0
- package/src/hooks/ts/session-start/initialize-session.ts +155 -0
- package/src/hooks/ts/session-start/load-core-context.ts +104 -0
- package/src/hooks/ts/session-start/load-project-context.ts +394 -0
- package/src/hooks/ts/stop/stop-hook.ts +407 -0
- package/src/hooks/ts/subagent-stop/subagent-stop-hook.ts +212 -0
- package/src/hooks/ts/user-prompt/cleanup-session-files.ts +45 -0
- package/src/hooks/ts/user-prompt/update-tab-titles.ts +88 -0
- package/tab-color-command.sh +24 -0
- package/templates/skills/createskill-skill.template.md +78 -0
- package/templates/skills/history-system.template.md +371 -0
- package/templates/skills/hook-system.template.md +913 -0
- package/templates/skills/sessions-skill.template.md +102 -0
- package/templates/skills/skill-system.template.md +214 -0
- package/templates/skills/terminal-tabs.template.md +120 -0
- package/dist/search-GK0ibTJy.mjs.map +0 -1
- package/dist/tools-CUg0Lyg-.mjs.map +0 -1
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
<!-- Generated by PAI Setup -->
|
|
2
|
+
# Hook System
|
|
3
|
+
|
|
4
|
+
**Event-Driven Automation Infrastructure**
|
|
5
|
+
|
|
6
|
+
**Location:** `${PAI_DIR}/Hooks/`
|
|
7
|
+
**Configuration:** `~/.claude/settings.json`
|
|
8
|
+
**Status:** Configure during `pai setup`
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
The PAI hook system is an event-driven automation infrastructure built on Claude Code's native hook support. Hooks are executable scripts (TypeScript/Python) that run automatically in response to specific events during Claude Code sessions.
|
|
15
|
+
|
|
16
|
+
**Core Capabilities:**
|
|
17
|
+
- **Session Management** - Auto-load context, capture summaries, manage state
|
|
18
|
+
- **Voice Notifications** - Text-to-speech announcements for task completions
|
|
19
|
+
- **History Capture** - Automatic work/learning documentation to `${PAI_DIR}/History/`
|
|
20
|
+
- **Multi-Agent Support** - Agent-specific hooks with voice routing
|
|
21
|
+
- **Observability** - Real-time event streaming to dashboard
|
|
22
|
+
- **Tab Titles** - Dynamic terminal tab updates with task context
|
|
23
|
+
|
|
24
|
+
**Key Principle:** Hooks run asynchronously and fail gracefully. They enhance the user experience but never block Claude Code's core functionality.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Available Hook Types
|
|
29
|
+
|
|
30
|
+
Claude Code supports the following hook events:
|
|
31
|
+
|
|
32
|
+
### 1. **SessionStart**
|
|
33
|
+
**When:** Claude Code session begins (new conversation)
|
|
34
|
+
**Use Cases:**
|
|
35
|
+
- Load PAI context from `skills/CORE/SKILL.md`
|
|
36
|
+
- Initialize session state
|
|
37
|
+
- Capture session metadata
|
|
38
|
+
|
|
39
|
+
**Example Configuration:**
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"SessionStart": [
|
|
43
|
+
{
|
|
44
|
+
"hooks": [
|
|
45
|
+
{
|
|
46
|
+
"type": "command",
|
|
47
|
+
"command": "${PAI_DIR}/Hooks/load-core-context.ts"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "command",
|
|
51
|
+
"command": "${PAI_DIR}/Hooks/initialize-pai-session.ts"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type SessionStart"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**What They Do:**
|
|
64
|
+
- `load-core-context.ts` - Reads `skills/CORE/SKILL.md` and injects PAI context as `<system-reminder>` at session start
|
|
65
|
+
- `initialize-pai-session.ts` - Sets up session state and environment
|
|
66
|
+
- `capture-all-events.ts` - Logs event to `${PAI_DIR}/History/raw-outputs/YYYY-MM/YYYY-MM-DD_all-events.jsonl`
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 2. **SessionEnd**
|
|
71
|
+
**When:** Claude Code session terminates (conversation ends)
|
|
72
|
+
**Use Cases:**
|
|
73
|
+
- Generate session summaries
|
|
74
|
+
- Save session metadata
|
|
75
|
+
- Cleanup temporary state
|
|
76
|
+
|
|
77
|
+
**Example Configuration:**
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"SessionEnd": [
|
|
81
|
+
{
|
|
82
|
+
"hooks": [
|
|
83
|
+
{
|
|
84
|
+
"type": "command",
|
|
85
|
+
"command": "${PAI_DIR}/Hooks/capture-session-summary.ts"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "command",
|
|
89
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type SessionEnd"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**What They Do:**
|
|
98
|
+
- `capture-session-summary.ts` - Analyzes session activity and creates summary document in `${PAI_DIR}/History/sessions/YYYY-MM/`
|
|
99
|
+
- Captures: files changed, commands executed, tools used, session focus, duration
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 3. **UserPromptSubmit**
|
|
104
|
+
**When:** User submits a new prompt to Claude
|
|
105
|
+
**Use Cases:**
|
|
106
|
+
- Update UI indicators
|
|
107
|
+
- Pre-process user input
|
|
108
|
+
- Capture prompts for analysis
|
|
109
|
+
|
|
110
|
+
**Example Configuration:**
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"UserPromptSubmit": [
|
|
114
|
+
{
|
|
115
|
+
"hooks": [
|
|
116
|
+
{
|
|
117
|
+
"type": "command",
|
|
118
|
+
"command": "${PAI_DIR}/Hooks/update-tab-titles.ts"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "command",
|
|
122
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type UserPromptSubmit"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**What They Do:**
|
|
131
|
+
- `update-tab-titles.ts` - Updates terminal tab title with task summary
|
|
132
|
+
- Launches background summarization for better tab titles
|
|
133
|
+
- Sets a processing indicator prefix
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### 4. **Stop**
|
|
138
|
+
**When:** Main agent completes a response
|
|
139
|
+
**Use Cases:**
|
|
140
|
+
- Voice notifications for task completion
|
|
141
|
+
- Capture work summaries and learnings
|
|
142
|
+
- Update terminal tab with completion status
|
|
143
|
+
|
|
144
|
+
**Example Configuration:**
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"Stop": [
|
|
148
|
+
{
|
|
149
|
+
"hooks": [
|
|
150
|
+
{
|
|
151
|
+
"type": "command",
|
|
152
|
+
"command": "${PAI_DIR}/Hooks/stop-hook.ts"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"type": "command",
|
|
156
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type Stop"
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**What They Do:**
|
|
165
|
+
- `stop-hook.ts` - THE CRITICAL HOOK for main agent completions
|
|
166
|
+
- Extracts `🎯 COMPLETED:` line from response
|
|
167
|
+
- Sends to voice server for TTS announcement
|
|
168
|
+
- Captures work summaries to `${PAI_DIR}/History/sessions/YYYY-MM/` or learnings to `${PAI_DIR}/History/learnings/YYYY-MM/`
|
|
169
|
+
- Updates terminal tab with completion indicator
|
|
170
|
+
- Sends event to observability dashboard
|
|
171
|
+
|
|
172
|
+
**Learning Detection:** Automatically identifies learning moments (2+ indicators: problem/issue/bug, fixed/solved, troubleshoot/debug, lesson/takeaway)
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 5. **SubagentStop**
|
|
177
|
+
**When:** Subagent (Task tool) completes execution
|
|
178
|
+
**Use Cases:**
|
|
179
|
+
- Agent-specific voice notifications
|
|
180
|
+
- Capture agent outputs
|
|
181
|
+
- Track multi-agent workflows
|
|
182
|
+
|
|
183
|
+
**Example Configuration:**
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"SubagentStop": [
|
|
187
|
+
{
|
|
188
|
+
"hooks": [
|
|
189
|
+
{
|
|
190
|
+
"type": "command",
|
|
191
|
+
"command": "${PAI_DIR}/Hooks/subagent-stop-hook.ts"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"type": "command",
|
|
195
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type SubagentStop"
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**What They Do:**
|
|
204
|
+
- `subagent-stop-hook.ts` - Agent-specific completion handling
|
|
205
|
+
- Waits for Task tool result in transcript
|
|
206
|
+
- Extracts `[AGENT:type]` tag and completion message
|
|
207
|
+
- Routes to agent-specific voice (via agent's own voice notification in response)
|
|
208
|
+
- Captures agent output to appropriate history category
|
|
209
|
+
- Sends to observability dashboard
|
|
210
|
+
|
|
211
|
+
**Agent-Specific Routing:**
|
|
212
|
+
- `[AGENT:engineer]` → Engineer voice
|
|
213
|
+
- `[AGENT:researcher]` → Researcher voice
|
|
214
|
+
- `[AGENT:pentester]` → Pentester voice
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### 6. **PreToolUse**
|
|
219
|
+
**When:** Before Claude executes any tool
|
|
220
|
+
**Use Cases:**
|
|
221
|
+
- Tool usage analytics
|
|
222
|
+
- Pre-execution validation
|
|
223
|
+
- Performance monitoring
|
|
224
|
+
|
|
225
|
+
**Example Configuration:**
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"PreToolUse": [
|
|
229
|
+
{
|
|
230
|
+
"matcher": "*",
|
|
231
|
+
"hooks": [
|
|
232
|
+
{
|
|
233
|
+
"type": "command",
|
|
234
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type PreToolUse"
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**What They Do:**
|
|
243
|
+
- Captures tool name, input parameters, timestamp
|
|
244
|
+
- Logs to daily events file for analysis
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### 7. **PostToolUse**
|
|
249
|
+
**When:** After Claude executes any tool
|
|
250
|
+
**Use Cases:**
|
|
251
|
+
- Capture tool outputs
|
|
252
|
+
- Error tracking
|
|
253
|
+
- Performance metrics
|
|
254
|
+
|
|
255
|
+
**Example Configuration:**
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"PostToolUse": [
|
|
259
|
+
{
|
|
260
|
+
"matcher": "*",
|
|
261
|
+
"hooks": [
|
|
262
|
+
{
|
|
263
|
+
"type": "command",
|
|
264
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type PostToolUse"
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**What They Do:**
|
|
273
|
+
- Captures tool output, execution time, success/failure
|
|
274
|
+
- Logs to `${PAI_DIR}/History/raw-outputs/YYYY-MM/YYYY-MM-DD_all-events.jsonl`
|
|
275
|
+
- Powers observability dashboard
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### 8. **PreCompact**
|
|
280
|
+
**When:** Before Claude compacts context (long conversations)
|
|
281
|
+
**Use Cases:**
|
|
282
|
+
- Preserve important context
|
|
283
|
+
- Log compaction events
|
|
284
|
+
- Pre-compaction cleanup
|
|
285
|
+
|
|
286
|
+
**Example Configuration:**
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"PreCompact": [
|
|
290
|
+
{
|
|
291
|
+
"matcher": "",
|
|
292
|
+
"hooks": [
|
|
293
|
+
{
|
|
294
|
+
"type": "command",
|
|
295
|
+
"command": "${PAI_DIR}/Hooks/context-compression-hook.ts"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"type": "command",
|
|
299
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.ts --event-type PreCompact"
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
]
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**What They Do:**
|
|
308
|
+
- `context-compression-hook.ts` - Handles context preservation before compaction
|
|
309
|
+
- Captures metadata about compaction events
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Configuration
|
|
314
|
+
|
|
315
|
+
### Location
|
|
316
|
+
**File:** `~/.claude/settings.json`
|
|
317
|
+
**Section:** `"hooks": { ... }`
|
|
318
|
+
|
|
319
|
+
### Environment Variables
|
|
320
|
+
Hooks have access to all environment variables from `~/.claude/settings.json` `"env"` section:
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"env": {
|
|
325
|
+
"PAI_DIR": "${HOME}/.claude",
|
|
326
|
+
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000"
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Key Variables:**
|
|
332
|
+
- `PAI_DIR` - PAI installation directory (always `${HOME}/.claude` or `~/.claude`)
|
|
333
|
+
- Hook scripts reference `${PAI_DIR}` in command paths
|
|
334
|
+
|
|
335
|
+
### Hook Configuration Structure
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"hooks": {
|
|
340
|
+
"HookEventName": [
|
|
341
|
+
{
|
|
342
|
+
"matcher": "pattern",
|
|
343
|
+
"hooks": [
|
|
344
|
+
{
|
|
345
|
+
"type": "command",
|
|
346
|
+
"command": "${PAI_DIR}/Hooks/my-hook.ts --arg value"
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Fields:**
|
|
356
|
+
- `HookEventName` - One of: SessionStart, SessionEnd, UserPromptSubmit, Stop, SubagentStop, PreToolUse, PostToolUse, PreCompact
|
|
357
|
+
- `matcher` - Pattern to match (use `"*"` for all tools, or specific tool names)
|
|
358
|
+
- `type` - Always `"command"` (executes external script)
|
|
359
|
+
- `command` - Path to executable hook script (TypeScript/Python/Bash)
|
|
360
|
+
|
|
361
|
+
### Hook Input (stdin)
|
|
362
|
+
All hooks receive JSON data on stdin:
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
{
|
|
366
|
+
session_id: string; // Unique session identifier
|
|
367
|
+
transcript_path: string; // Path to JSONL transcript
|
|
368
|
+
hook_event_name: string; // Event that triggered hook
|
|
369
|
+
prompt?: string; // User prompt (UserPromptSubmit only)
|
|
370
|
+
tool_name?: string; // Tool name (PreToolUse/PostToolUse)
|
|
371
|
+
tool_input?: any; // Tool parameters (PreToolUse)
|
|
372
|
+
tool_output?: any; // Tool result (PostToolUse)
|
|
373
|
+
// ... event-specific fields
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Common Patterns
|
|
380
|
+
|
|
381
|
+
### 1. Voice Notifications
|
|
382
|
+
|
|
383
|
+
**Pattern:** Extract completion message → Send to voice server
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// stop-hook.ts pattern
|
|
387
|
+
const completionMessage = extractCompletion(lastMessage);
|
|
388
|
+
|
|
389
|
+
const payload = {
|
|
390
|
+
title: 'PAI',
|
|
391
|
+
message: completionMessage,
|
|
392
|
+
voice_enabled: true,
|
|
393
|
+
voice_id: 'YOUR_VOICE_ID' // Configure with your ElevenLabs voice
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
await fetch('http://localhost:8888/notify', {
|
|
397
|
+
method: 'POST',
|
|
398
|
+
headers: { 'Content-Type': 'application/json' },
|
|
399
|
+
body: JSON.stringify(payload)
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Configure voice IDs in your `~/.claude/settings.json` env section.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
### 2. History Capture (UOCS Pattern)
|
|
408
|
+
|
|
409
|
+
**Pattern:** Parse structured response → Save to appropriate history directory
|
|
410
|
+
|
|
411
|
+
**File Naming Convention:**
|
|
412
|
+
```
|
|
413
|
+
YYYY-MM-DD-HHMMSS_TYPE_description.md
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Types:**
|
|
417
|
+
- `WORK` - General task completions
|
|
418
|
+
- `LEARNING` - Problem-solving learnings
|
|
419
|
+
- `SESSION` - Session summaries
|
|
420
|
+
- `RESEARCH` - Research findings (from agents)
|
|
421
|
+
- `FEATURE` - Feature implementations (from agents)
|
|
422
|
+
- `DECISION` - Architectural decisions (from agents)
|
|
423
|
+
|
|
424
|
+
**Structured Sections Parsed:**
|
|
425
|
+
- `📋 SUMMARY:` - Brief overview
|
|
426
|
+
- `🔍 ANALYSIS:` - Key findings
|
|
427
|
+
- `⚡ ACTIONS:` - Steps taken
|
|
428
|
+
- `✅ RESULTS:` - Outcomes
|
|
429
|
+
- `📊 STATUS:` - Current state
|
|
430
|
+
- `➡️ NEXT:` - Follow-up actions
|
|
431
|
+
- `🎯 COMPLETED:` - **Voice notification line**
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
### 3. Agent Type Detection
|
|
436
|
+
|
|
437
|
+
**Pattern:** Identify which agent is executing → Route appropriately
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
// Agent detection patterns
|
|
441
|
+
let agentName = 'main';
|
|
442
|
+
|
|
443
|
+
// Detect from Task tool
|
|
444
|
+
if (hookData.tool_name === 'Task' && hookData.tool_input?.subagent_type) {
|
|
445
|
+
agentName = hookData.tool_input.subagent_type;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Detect from env variable
|
|
449
|
+
else if (process.env.CLAUDE_CODE_AGENT) {
|
|
450
|
+
agentName = process.env.CLAUDE_CODE_AGENT;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Detect from path
|
|
454
|
+
else if (hookData.cwd && hookData.cwd.includes('/Agents/')) {
|
|
455
|
+
const agentMatch = hookData.cwd.match(/\/agents\/([^\/]+)/i);
|
|
456
|
+
if (agentMatch) agentName = agentMatch[1];
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Session Mapping:** `${PAI_DIR}/agent-sessions.json`
|
|
461
|
+
```json
|
|
462
|
+
{
|
|
463
|
+
"session-id-abc123": "engineer",
|
|
464
|
+
"session-id-def456": "researcher"
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
### 4. Observability Integration
|
|
471
|
+
|
|
472
|
+
**Pattern:** Send event to dashboard → Fail silently if offline
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
await sendEventToObservability({
|
|
476
|
+
source_app: agentName,
|
|
477
|
+
session_id: hookInput.session_id,
|
|
478
|
+
hook_event_type: 'Stop',
|
|
479
|
+
timestamp: getCurrentTimestamp(),
|
|
480
|
+
transcript_path: hookInput.transcript_path,
|
|
481
|
+
summary: completionMessage,
|
|
482
|
+
}).catch(() => {
|
|
483
|
+
// Silently fail - dashboard may not be running
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Dashboard URLs:**
|
|
488
|
+
- Server: `http://localhost:4000`
|
|
489
|
+
- Client: `http://localhost:5173`
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
### 5. Async Non-Blocking Execution
|
|
494
|
+
|
|
495
|
+
**Pattern:** Hook executes quickly → Launch background processes for slow operations
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
// Set immediate tab title (fast)
|
|
499
|
+
process.stderr.write(`\x1b]0;${titleWithEmoji}\x07`);
|
|
500
|
+
|
|
501
|
+
// Launch background process for AI summary (slow)
|
|
502
|
+
Bun.spawn(['bun', `${paiDir}/Hooks/update-tab-title.ts`, prompt], {
|
|
503
|
+
stdout: 'ignore',
|
|
504
|
+
stderr: 'ignore',
|
|
505
|
+
stdin: 'ignore'
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
process.exit(0); // Exit immediately
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Key Principle:** Hooks must never block Claude Code. Always exit quickly, use background processes for slow work.
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
### 6. Graceful Failure
|
|
516
|
+
|
|
517
|
+
**Pattern:** Wrap everything in try/catch → Log errors → Exit successfully
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
async function main() {
|
|
521
|
+
try {
|
|
522
|
+
// Hook logic here
|
|
523
|
+
} catch (error) {
|
|
524
|
+
// Log but don't fail
|
|
525
|
+
console.error('Hook error:', error);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
process.exit(0); // Always exit 0
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Why:** If hooks crash, Claude Code may freeze. Always exit cleanly.
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Creating Custom Hooks
|
|
537
|
+
|
|
538
|
+
### Step 1: Choose Hook Event
|
|
539
|
+
Decide which event should trigger your hook (SessionStart, Stop, PostToolUse, etc.)
|
|
540
|
+
|
|
541
|
+
### Step 2: Create Hook Script
|
|
542
|
+
**Location:** `${PAI_DIR}/Hooks/my-custom-hook.ts`
|
|
543
|
+
|
|
544
|
+
**Template:**
|
|
545
|
+
```typescript
|
|
546
|
+
#!/usr/bin/env bun
|
|
547
|
+
|
|
548
|
+
interface HookInput {
|
|
549
|
+
session_id: string;
|
|
550
|
+
transcript_path: string;
|
|
551
|
+
hook_event_name: string;
|
|
552
|
+
// ... event-specific fields
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function main() {
|
|
556
|
+
try {
|
|
557
|
+
// Read stdin
|
|
558
|
+
const input = await Bun.stdin.text();
|
|
559
|
+
const data: HookInput = JSON.parse(input);
|
|
560
|
+
|
|
561
|
+
// Your hook logic here
|
|
562
|
+
console.log(`Hook triggered: ${data.hook_event_name}`);
|
|
563
|
+
|
|
564
|
+
// Example: Read transcript
|
|
565
|
+
const fs = require('fs');
|
|
566
|
+
const transcript = fs.readFileSync(data.transcript_path, 'utf-8');
|
|
567
|
+
|
|
568
|
+
// Do something with the data
|
|
569
|
+
|
|
570
|
+
} catch (error) {
|
|
571
|
+
// Log but don't fail
|
|
572
|
+
console.error('Hook error:', error);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
process.exit(0); // Always exit 0
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
main();
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Step 3: Make Executable
|
|
582
|
+
```bash
|
|
583
|
+
chmod +x ${PAI_DIR}/Hooks/my-custom-hook.ts
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Step 4: Add to settings.json
|
|
587
|
+
```json
|
|
588
|
+
{
|
|
589
|
+
"hooks": {
|
|
590
|
+
"Stop": [
|
|
591
|
+
{
|
|
592
|
+
"hooks": [
|
|
593
|
+
{
|
|
594
|
+
"type": "command",
|
|
595
|
+
"command": "${PAI_DIR}/Hooks/my-custom-hook.ts"
|
|
596
|
+
}
|
|
597
|
+
]
|
|
598
|
+
}
|
|
599
|
+
]
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Step 5: Test
|
|
605
|
+
```bash
|
|
606
|
+
# Test hook directly
|
|
607
|
+
echo '{"session_id":"test","transcript_path":"/tmp/test.jsonl","hook_event_name":"Stop"}' | bun ${PAI_DIR}/Hooks/my-custom-hook.ts
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Step 6: Restart Claude Code
|
|
611
|
+
Hooks are loaded at startup. Restart to apply changes.
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## Hook Development Best Practices
|
|
616
|
+
|
|
617
|
+
### 1. **Fast Execution**
|
|
618
|
+
- Hooks should complete in < 500ms
|
|
619
|
+
- Use background processes for slow work (AI API calls, file processing)
|
|
620
|
+
- Exit immediately after launching background work
|
|
621
|
+
|
|
622
|
+
### 2. **Graceful Failure**
|
|
623
|
+
- Always wrap in try/catch
|
|
624
|
+
- Log errors to stderr (available in hook debug logs)
|
|
625
|
+
- Always `process.exit(0)` - never throw or exit(1)
|
|
626
|
+
|
|
627
|
+
### 3. **Non-Blocking**
|
|
628
|
+
- Never wait for external services (unless they respond quickly)
|
|
629
|
+
- Use `.catch(() => {})` for async operations
|
|
630
|
+
- Fail silently if optional services are offline
|
|
631
|
+
|
|
632
|
+
### 4. **Stdin Reading**
|
|
633
|
+
- Use timeout when reading stdin (Claude Code may not send data immediately)
|
|
634
|
+
- Handle empty/invalid input gracefully
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
const decoder = new TextDecoder();
|
|
638
|
+
const reader = Bun.stdin.stream().getReader();
|
|
639
|
+
|
|
640
|
+
const timeoutPromise = new Promise<void>((resolve) => {
|
|
641
|
+
setTimeout(() => resolve(), 500); // 500ms timeout
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
await Promise.race([readPromise, timeoutPromise]);
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### 5. **File I/O**
|
|
648
|
+
- Check `existsSync()` before reading files
|
|
649
|
+
- Create directories with `{ recursive: true }`
|
|
650
|
+
|
|
651
|
+
### 6. **Environment Access**
|
|
652
|
+
- All `settings.json` env vars available via `process.env`
|
|
653
|
+
- Use `${PAI_DIR}` in settings.json for portability
|
|
654
|
+
- Access in code via `process.env.PAI_DIR`
|
|
655
|
+
|
|
656
|
+
### 7. **Observability**
|
|
657
|
+
- Send events to dashboard for visibility
|
|
658
|
+
- Include all relevant metadata (session_id, tool_name, etc.)
|
|
659
|
+
- Use `.catch(() => {})` - dashboard may be offline
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## Troubleshooting
|
|
664
|
+
|
|
665
|
+
### Hook Not Running
|
|
666
|
+
|
|
667
|
+
**Check:**
|
|
668
|
+
1. Is hook script executable? `chmod +x ${PAI_DIR}/Hooks/my-hook.ts`
|
|
669
|
+
2. Is path correct in settings.json? Use `${PAI_DIR}/Hooks/...`
|
|
670
|
+
3. Is settings.json valid JSON? `jq . ~/.claude/settings.json`
|
|
671
|
+
4. Did you restart Claude Code after editing settings.json?
|
|
672
|
+
|
|
673
|
+
**Debug:**
|
|
674
|
+
```bash
|
|
675
|
+
# Test hook directly
|
|
676
|
+
echo '{"session_id":"test","transcript_path":"/tmp/test.jsonl","hook_event_name":"Stop"}' | bun ${PAI_DIR}/Hooks/my-hook.ts
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
### Hook Hangs/Freezes Claude Code
|
|
682
|
+
|
|
683
|
+
**Cause:** Hook not exiting (infinite loop, waiting for input, blocking operation)
|
|
684
|
+
|
|
685
|
+
**Fix:**
|
|
686
|
+
1. Add timeouts to all blocking operations
|
|
687
|
+
2. Ensure `process.exit(0)` is always reached
|
|
688
|
+
3. Use background processes for long operations
|
|
689
|
+
4. Check stdin reading has timeout
|
|
690
|
+
|
|
691
|
+
**Prevention:**
|
|
692
|
+
```typescript
|
|
693
|
+
// Always use timeout
|
|
694
|
+
setTimeout(() => {
|
|
695
|
+
console.error('Hook timeout - exiting');
|
|
696
|
+
process.exit(0);
|
|
697
|
+
}, 5000); // 5 second max
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
702
|
+
### Voice Notifications Not Working
|
|
703
|
+
|
|
704
|
+
**Check:**
|
|
705
|
+
1. Is voice server running? `curl http://localhost:8888/health`
|
|
706
|
+
2. Is voice_id correct? See your voice configuration
|
|
707
|
+
3. Is message format correct? `{"message":"...", "voice_id":"...", "title":"..."}`
|
|
708
|
+
|
|
709
|
+
**Debug:**
|
|
710
|
+
```bash
|
|
711
|
+
# Test voice server directly
|
|
712
|
+
curl -X POST http://localhost:8888/notify \
|
|
713
|
+
-H "Content-Type: application/json" \
|
|
714
|
+
-d '{"message":"Test message","voice_id":"YOUR_VOICE_ID","title":"Test"}'
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
**Common Issues:**
|
|
718
|
+
- Wrong voice_id → Silent failure (invalid ID)
|
|
719
|
+
- Voice server offline → Hook continues (graceful failure)
|
|
720
|
+
- No `🎯 COMPLETED:` line → No voice notification extracted
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
### History Not Capturing
|
|
725
|
+
|
|
726
|
+
**Check:**
|
|
727
|
+
1. Does `${PAI_DIR}/History/` directory exist?
|
|
728
|
+
2. Are structured sections present in response? (`📋 SUMMARY:`, `🎯 COMPLETED:`, etc.)
|
|
729
|
+
3. Is hook actually running? Check `${PAI_DIR}/History/raw-outputs/` for events
|
|
730
|
+
4. File permissions? `ls -la ${PAI_DIR}/History/sessions/`
|
|
731
|
+
|
|
732
|
+
**Debug:**
|
|
733
|
+
```bash
|
|
734
|
+
# Check recent captures
|
|
735
|
+
ls -lt ${PAI_DIR}/History/sessions/$(date +%Y-%m)/ | head -10
|
|
736
|
+
|
|
737
|
+
# Check raw events
|
|
738
|
+
tail ${PAI_DIR}/History/raw-outputs/$(date +%Y-%m)/$(date +%Y-%m-%d)_all-events.jsonl
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
### Agent Detection Failing
|
|
744
|
+
|
|
745
|
+
**Check:**
|
|
746
|
+
1. Is `${PAI_DIR}/agent-sessions.json` writable?
|
|
747
|
+
2. Is `[AGENT:type]` tag in `🎯 COMPLETED:` line?
|
|
748
|
+
3. Is agent running from correct directory?
|
|
749
|
+
|
|
750
|
+
**Fix:**
|
|
751
|
+
- Ensure agents include `[AGENT:type]` in completion line
|
|
752
|
+
- Verify Task tool passes `subagent_type` parameter
|
|
753
|
+
|
|
754
|
+
---
|
|
755
|
+
|
|
756
|
+
## Advanced Topics
|
|
757
|
+
|
|
758
|
+
### Multi-Hook Execution Order
|
|
759
|
+
|
|
760
|
+
Hooks in same event execute **sequentially** in order defined in settings.json:
|
|
761
|
+
|
|
762
|
+
```json
|
|
763
|
+
{
|
|
764
|
+
"Stop": [
|
|
765
|
+
{
|
|
766
|
+
"hooks": [
|
|
767
|
+
{ "command": "${PAI_DIR}/Hooks/stop-hook.ts" }, // Runs first
|
|
768
|
+
{ "command": "${PAI_DIR}/Hooks/capture-all-events.ts" } // Runs second
|
|
769
|
+
]
|
|
770
|
+
}
|
|
771
|
+
]
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
**Note:** If first hook hangs, second won't run. Keep hooks fast!
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
### Matcher Patterns
|
|
780
|
+
|
|
781
|
+
`"matcher"` field filters which events trigger hook:
|
|
782
|
+
|
|
783
|
+
```json
|
|
784
|
+
{
|
|
785
|
+
"PostToolUse": [
|
|
786
|
+
{
|
|
787
|
+
"matcher": "Bash", // Only Bash tool executions
|
|
788
|
+
"hooks": [...]
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"matcher": "*", // All tool executions
|
|
792
|
+
"hooks": [...]
|
|
793
|
+
}
|
|
794
|
+
]
|
|
795
|
+
}
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
**Patterns:**
|
|
799
|
+
- `"*"` - All events
|
|
800
|
+
- `"Bash"` - Specific tool name
|
|
801
|
+
- `""` - Empty (all events, same as `*`)
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
### Hook Data Payloads by Event Type
|
|
806
|
+
|
|
807
|
+
**SessionStart:**
|
|
808
|
+
```typescript
|
|
809
|
+
{
|
|
810
|
+
session_id: string;
|
|
811
|
+
transcript_path: string;
|
|
812
|
+
hook_event_name: "SessionStart";
|
|
813
|
+
cwd: string;
|
|
814
|
+
}
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
**UserPromptSubmit:**
|
|
818
|
+
```typescript
|
|
819
|
+
{
|
|
820
|
+
session_id: string;
|
|
821
|
+
transcript_path: string;
|
|
822
|
+
hook_event_name: "UserPromptSubmit";
|
|
823
|
+
prompt: string; // The user's prompt text
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
**PreToolUse:**
|
|
828
|
+
```typescript
|
|
829
|
+
{
|
|
830
|
+
session_id: string;
|
|
831
|
+
transcript_path: string;
|
|
832
|
+
hook_event_name: "PreToolUse";
|
|
833
|
+
tool_name: string;
|
|
834
|
+
tool_input: any; // Tool parameters
|
|
835
|
+
}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
**PostToolUse:**
|
|
839
|
+
```typescript
|
|
840
|
+
{
|
|
841
|
+
session_id: string;
|
|
842
|
+
transcript_path: string;
|
|
843
|
+
hook_event_name: "PostToolUse";
|
|
844
|
+
tool_name: string;
|
|
845
|
+
tool_input: any;
|
|
846
|
+
tool_output: any; // Tool result
|
|
847
|
+
error?: string; // If tool failed
|
|
848
|
+
}
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
**Stop:**
|
|
852
|
+
```typescript
|
|
853
|
+
{
|
|
854
|
+
session_id: string;
|
|
855
|
+
transcript_path: string;
|
|
856
|
+
hook_event_name: "Stop";
|
|
857
|
+
}
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
**SubagentStop:**
|
|
861
|
+
```typescript
|
|
862
|
+
{
|
|
863
|
+
session_id: string;
|
|
864
|
+
transcript_path: string;
|
|
865
|
+
hook_event_name: "SubagentStop";
|
|
866
|
+
}
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
**SessionEnd:**
|
|
870
|
+
```typescript
|
|
871
|
+
{
|
|
872
|
+
conversation_id: string; // Note: different field name
|
|
873
|
+
timestamp: string;
|
|
874
|
+
}
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
---
|
|
878
|
+
|
|
879
|
+
## Quick Reference Card
|
|
880
|
+
|
|
881
|
+
```
|
|
882
|
+
HOOK LIFECYCLE:
|
|
883
|
+
1. Event occurs (SessionStart, Stop, etc.)
|
|
884
|
+
2. Claude Code writes hook data to stdin
|
|
885
|
+
3. Hook script executes
|
|
886
|
+
4. Hook reads stdin (with timeout)
|
|
887
|
+
5. Hook performs actions (voice, capture, etc.)
|
|
888
|
+
6. Hook exits 0 (always succeeds)
|
|
889
|
+
7. Claude Code continues
|
|
890
|
+
|
|
891
|
+
KEY FILES:
|
|
892
|
+
~/.claude/settings.json Hook configuration
|
|
893
|
+
${PAI_DIR}/Hooks/ Hook scripts
|
|
894
|
+
${PAI_DIR}/History/raw-outputs/ Event logs (JSONL)
|
|
895
|
+
${PAI_DIR}/History/sessions/ Work summaries
|
|
896
|
+
${PAI_DIR}/History/learnings/ Learning captures
|
|
897
|
+
${PAI_DIR}/agent-sessions.json Session→Agent mapping
|
|
898
|
+
|
|
899
|
+
CRITICAL HOOKS:
|
|
900
|
+
stop-hook.ts Voice + history capture (main agent)
|
|
901
|
+
subagent-stop-hook.ts Voice + history capture (subagents)
|
|
902
|
+
load-core-context.ts PAI context loading
|
|
903
|
+
capture-all-events.ts Universal event logger
|
|
904
|
+
|
|
905
|
+
VOICE SERVER:
|
|
906
|
+
URL: http://localhost:8888/notify
|
|
907
|
+
Payload: {"message":"...", "voice_id":"...", "title":"..."}
|
|
908
|
+
|
|
909
|
+
OBSERVABILITY:
|
|
910
|
+
Server: http://localhost:4000
|
|
911
|
+
Client: http://localhost:5173
|
|
912
|
+
Events: All hooks send to /events endpoint
|
|
913
|
+
```
|