fix(ingest): self-heal the Claude/Codex session-ingest hook#25
Merged
Conversation
The `kai log ingest` hook is registered by `kai init` with the path of the currently-running binary (os.Executable()). During a Claude Code session that is often an ephemeral copy in a temp scratchpad, so the absolute path baked into .claude/settings.local.json / .codex/hooks.json dies when the scratchpad is cleaned — and every session afterward silently logs nothing. Changes: - Bake a durable path into hooks: prefer ~/.kai/bin/kai, fall back to the running binary only if it isn't under a temp dir, else bare "kai" (PATH). - reconcileHookEvents(): prune stale ingest entries (dead/temp paths, old installs) and install the current one, without touching unrelated hooks. - Self-heal on every invocation (PersistentPreRun): repair-only — fix an existing ingest hook's stale path, never create a fresh install. - Root ingest at the git project, and never treat the global ~/.kai config dir as a repo root — previously sessions in repos without a local .kai walked up to $HOME and misfiled records into ~/.kai/loops (which didn't exist), so nothing was ever written. - `kai doctor` now audits ingest: hook installed? binary reachable? records being produced? `kai doctor --fix` repairs it. Bumps version 0.34.2 -> 0.34.3.
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.
Problem
The
kai log ingesthook (registered bykai init, fired on Claude Code / CodexStop+SessionEnd) writes a machine-readable loop record to<repo>/.kai/loops/<session>.jsonfor the desktop Overview/Loops views. It was silently logging nothing:os.Executable(). During a Claude Code run that's often an ephemeral copy in a temp scratchpad (/tmp/claude-.../scratchpad/kai); when the scratchpad is cleaned the path dies and every session afterward no-ops.$HOME. Repos here have.gitbut no local.kai/, so the "nearest.kaiancestor" logic walked all the way up to the global~/.kaiconfig dir → root resolved to$HOME→ records aimed at~/.kai/loops, which doesn't exist. Nothing written.Observed: 4 repos, 0 loop records; two hooks pointing at dead temp copies, two with no hook.
Fix
stableKaiPath): prefer~/.kai/bin/kai, fall back to the running binary only if it isn't under a temp dir, else barekai(PATH).reconcileHookEvents: prune stale ingest entries (dead/temp paths, old installs) and install the current one — never touches unrelated hooks (TokenBar, prompt-logger).PersistentPreRun(selfHealAgentHooks): repair-only — fixes an existing ingest hook's stale path on anykaiinvocation; does not create fresh installs (that stays withkai init/kai doctor --fix).~/.kaifrom repo-root detection, so records land in<repo>/.kai/loopsinstead of$HOME.kai doctornow audits ingest (hook installed? binary reachable? records produced?);kai doctor --fixrepairs it.0.34.2→0.34.3.Verification
go build ./...,go vet, existing hook/ingest/doctor tests, and new unit tests (TestIsTempPath,TestReconcileHookEventsPrunesStale,TestReconcileHookEventsIdempotent) all pass.~/.kai/bin/kai; a simulatedStopevent wrote a real.kai/loops/<id>.json;kai doctorwent all-green.🤖 Generated with Claude Code