-
Notifications
You must be signed in to change notification settings - Fork 700
Closed
Description
Bug Report: stop-hook.ts never captures learnings due to missing response field
Summary
The stop-hook.ts in kai-history-system pack v1.0.0 expects a response field in the Stop event payload, but Claude Code never sends this field. This causes the hook to exit immediately on line 80, preventing all learning and session captures from being saved.
Impact
- ❌ Learnings are never captured -
history/learnings/remains empty - ❌ Sessions are never captured via stop-hook - Only SessionEnd hook creates summaries
- ❌ Core feature of history system is broken - Auto-categorization by learning indicators doesn't work
Evidence
What Claude Code Actually Sends
From history/raw-outputs/YYYY-MM/YYYY-MM-DD_all-events.jsonl:
{
"hook_event_type": "Stop",
"payload": {
"session_id": "8ab02882-5caf-4682-9f1e-2d3f059bd297",
"transcript_path": "/home/marko/.claude/projects/-home-marko--config-pai/8ab02882-5caf-4682-9f1e-2d3f059bd297.jsonl",
"cwd": "/home/marko/.config/pai",
"permission_mode": "acceptEdits",
"hook_event_name": "Stop",
"stop_hook_active": false
}
}
Note: No response field present.
What stop-hook.ts Expects
Packs/kai-history-system/src/stop-hook.ts lines 78-81:
const payload: StopPayload = JSON.parse(stdinData);
if (!payload.response) {
process.exit(0); // ❌ Always exits here
}
Root Cause
During the v2.0 refactor to directory-based structure (commit 1c34d06), the stop-hook was simplified from the working version that read transcripts. The older .claude/hooks/stop-hook.ts (commit 7b3031e) correctly handled this by:
1. Reading transcript_path from payload
2. Parsing the transcript JSONL file
3. Extracting the last assistant message
The simplified kai-history-system pack version removed this logic but forgot that Claude Code doesn't send a response field.
Reproduction Steps
1. Install kai-history-system pack v1.0.0
2. Complete any session with learning indicators (e.g., "I discovered the problem was X. The root cause was Y. After debugging, I fixed it by Z.")
3. Check $PAI_DIR/history/learnings/ - it will be empty
4. Check raw events log to confirm Stop hook was called but produced no output
Proposed Fix
Replace the response field check with transcript reading logic:
async function main() {
try {
const stdinData = await Bun.stdin.text();
if (!stdinData.trim()) {
process.exit(0);
}
const payload: StopPayload = JSON.parse(stdinData);
// Read transcript to get the last assistant response
if (!payload.transcript_path || !existsSync(payload.transcript_path)) {
process.exit(0);
}
const transcriptContent = readFileSync(payload.transcript_path, 'utf-8');
const lines = transcriptContent.trim().split('\n').filter(l => l.trim());
if (lines.length === 0) {
process.exit(0);
}
// Get last assistant message
let response = '';
for (let i = lines.length - 1; i >= 0; i--) {
try {
const entry = JSON.parse(lines[i]);
if (entry.type === 'assistant' && entry.message?.content) {
// Extract text from content array
const contentArray = Array.isArray(entry.message.content)
? entry.message.content
: [entry.message.content];
response = contentArray
.map(c => {
if (typeof c === 'string') return c;
if (c?.text) return c.text;
if (c?.content) return String(c.content);
return '';
})
.join('\n')
.trim();
if (response) break;
}
} catch (e) {
continue;
}
}
if (!response) {
process.exit(0);
}
// ... rest of existing logic continues unchanged
Also add readFileSync to imports:
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'fs';
Test Results
After applying the fix and testing with real Stop event payloads:
Test 1: SESSION Capture
$ cat real-stop-payload.json | ~/.config/pai/hooks/stop-hook.ts
📝 Captured SESSION to sessions/2026-01/20260103T122209_SESSION_uitstekende-vraag.md
✅ File created with correct content extracted from transcript
Test 2: LEARNING Detection
$ cat learning-payload.json | ~/.config/pai/hooks/stop-hook.ts
📝 Captured LEARNING to learnings/2026-01/20260103T122240_LEARNING_discovered-problem-root-cause.md
✅ Learning indicators correctly detected (8 keywords: discovered, problem, root cause, debugging, realized, solution, fixed, bug)
✅ File saved to learnings/ directory instead of sessions/
Environment
- OS: Linux (Ubuntu/Debian-based)
- Claude Code: Latest version (as of 2026-01-03)
- PAI Version: Kai Bundle v2.0.0
- Pack Version: kai-history-system v1.0.0
- Bun Version: 1.x
Additional Notes
- This bug affects all installations of kai-history-system pack v1.0.0
- The bug exists in both the initial install and the current GitHub main branch
- Commit b6bd951 fixed session_id field mismatch but didn't address the response field issue
- No open issues on GitHub currently reference this problem
Suggested Immediate Action
Update Packs/kai-history-system/src/stop-hook.ts with the transcript reading logic from the older working version (.claude/hooks/stop-hook.ts @ commit 7b3031e), adapted for the current pack structure.Sirnii
Metadata
Metadata
Assignees
Labels
No labels