feat(sensor): Zuhn-native session-capture hook (Option A)#5
Merged
Conversation
…-free) A Claude Code SessionEnd hook that captures the session transcript as a Zuhn "session" source. MECHANICAL only — no LLM in the hook. Insight extraction stays the deliberate, gated `npm run autoknowledge` step, so Phase 8's "no auto-extraction" still holds; only capture is automated. Why this and not claude-mem: claude-mem digests via a paid LLM API (no key in this env, install is interactive). Zuhn's autoknowledge already uses the authenticated `claude` CLI — so this path has zero new credentials, zero extra API cost, no background daemon. Components: - scripts/lib/transcript.ts — parseTranscript (JSONL → user-prompt + assistant-text turns; drops isSidechain, tool_use/tool_result, assistant thinking, non-conversation types, and framework-injection user turns matching <system-reminder>/<command-*>); renderConversation (caps to 60K chars keeping the TAIL with a truncation note); buildTranscriptSource (title=first user prompt; slug/id salted by session_id → idempotent; null when there's no usable conversation). - scripts/capture-session.ts — the hook script. Reads hook JSON on stdin (guards process.stdin.isTTY to avoid blocking on manual runs), graceful no-op on missing transcript, idempotent file-exists skip, --dry-run, and NEVER throws out of the hook (try/catch around every I/O; always exit 0). - templates/hooks/session-capture.sh — bash wrapper. Errors are LOGGED to ~/.claude/session-capture.log instead of silenced (a hook you can't watch fire is one where silent failure looks like "it works"). - docs/session-pipeline-setup.md — records the design supersession: the Phase-8 "explicit intent only" constraint existed because there was no automatic quality control; the gate now provides it, so passive transcript capture is safe. Frontmatter: "session" was already added to SourceFrontmatter.type / the health glob / the autoknowledge discovery glob in the claude-mem PR (#4), so session sources flow through the existing extract→gate path unchanged. Tests: 8 (noise-stripping edge cases, cap/tail, idempotency, null on empty). Verified end-to-end on the real 38MB transcript (→ 8831-word digest), on bogus input (graceful no-op), and via the logged hook chain with a synthetic transcript + temp KB. Local codex review stalled twice (the harness backgrounded `codex exec`, which hangs on stdin/tty in that mode). Relying on the GitHub codex App for PR review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's "Verify hook templates are executable" check caught that the Write tool created the template at 0644. The local copy installed in .claude/hooks/ was already chmod +x'd, but the template itself wasn't — so a fresh clone would copy a non-executable template into .claude/hooks/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A Claude Code
SessionEndhook that captures the session transcript as a Zuhnsessionsource. Mechanical only — no LLM in the hook. Insight extraction stays the deliberate, gatednpm run autoknowledgestep, so Phase 8's "no auto-extraction" still holds — only capture is automated.Why this path: claude-mem (the alternative) digests via a paid LLM API (no key set + interactive install). Zuhn's own
autoknowledgealready uses the authenticatedclaudeCLI — so this is zero new credentials, zero extra cost, no background daemon.What it does
Safety design
try/catcharound every I/O incapture-session.ts; bash wrapper alwaysexit 0;process.stdin.isTTYguard prevents blocking on manual runs.~/.claude/session-capture.log(was a real bug-shaped design when I had2>/dev/null; fixed).session_idand date-independent → same session always maps to the same file;existsSyncshort-circuits re-captures.isSidechain(subagent),tool_use/tool_result, assistantthinking,attachment/system/custom-titlelines, and framework-injection user turns (<system-reminder>/<command-*>).Records a deliberate design supersession
docs/session-pipeline-setup.mdupdated: Phase 8's "explicit intent only / no passive scraping" existed because there was no automatic quality control. The gate now provides it, so passive transcript capture is safe. Capture is automated; extraction (and quality enforcement) stay gated.Test plan
Note on review
Local
codex execreview stalled twice (the harness backgrounds long commands;codex exechangs on stdin/tty in that mode). Killed both. Relying on the GitHub codex App for PR review, plus the test coverage above.🤖 Generated with Claude Code