The contradiction
LifeOS/install/hooks/hooks.json (the manifest InstallHooks.ts installs from) never registers three hooks that ship in LifeOS/install/hooks/:
PostToolObserver.hook.ts — the consolidated sync catch-all PostToolUse dispatcher (its header: merges the two sync catch-all modules that emit additionalContext)
LoopDetector.hook.ts — exact-repeat / oscillation / hammering detection; per its dispatcher's design it is ONLY reachable through PostToolObserver
DriftReminder.hook.ts — voice/format drift nudges
But LIFEOS/DOCUMENTATION/Hooks/HookSystem.md describes them as live:
- Its post-consolidation summary lists
LoopDetector → PostToolObserver among the dispatcher imports and counts PostToolObserver among the consolidation targets.
- Its PostToolUse settings listing shows
PostToolObserver.hook.ts registered (catch-all, timeout 5).
- Its DriftReminder section says it is registered on UserPromptSubmit (user settings, async) + PostToolUseFailure (system settings).
Neither name has ever appeared in hooks.json history (git log -S comes back empty for both), and the shipped settings.system.json template carries no hooks block — so a fresh install gets no fire path for LoopDetector or DriftReminder at all. The consolidation's live registrations appear to have never been carried into the public install manifest.
Two smaller HookSystem.md nits in the same area:
- Its "8 files on disk but NOT registered directly" list omits
FormatGate.hook.ts, which StopGates.hook.ts imports first in its gate chain (FormatGate's header describes it as OutputFormatGate's successor with teeth, 2026-07-11) — so the dispatched-file count is 9, not 8.
- The "30 registered / 38 on disk" counts don't reconcile against the public payload (28 distinct files registered by hooks.json; 39 hook files shipped counting
ContextReduction.hook.sh).
Possible resolutions (maintainer's call on intent)
- Registration is intended → add
PostToolObserver (PostToolUse catch-all) and DriftReminder to hooks.json so installs match HookSystem.md.
- The lean manifest is intended → update HookSystem.md to mark these as shipped-but-optional, and note LoopDetector/DriftReminder are inactive by default.
Happy to PR either direction.
Context
Found while syncing hooks/README.md to registration truth (PR #1595, which documents the manifest as-is and stays neutral on this question).
The contradiction
LifeOS/install/hooks/hooks.json(the manifestInstallHooks.tsinstalls from) never registers three hooks that ship inLifeOS/install/hooks/:PostToolObserver.hook.ts— the consolidated sync catch-all PostToolUse dispatcher (its header: merges the two sync catch-all modules that emit additionalContext)LoopDetector.hook.ts— exact-repeat / oscillation / hammering detection; per its dispatcher's design it is ONLY reachable through PostToolObserverDriftReminder.hook.ts— voice/format drift nudgesBut
LIFEOS/DOCUMENTATION/Hooks/HookSystem.mddescribes them as live:LoopDetector → PostToolObserveramong the dispatcher imports and counts PostToolObserver among the consolidation targets.PostToolObserver.hook.tsregistered (catch-all, timeout 5).Neither name has ever appeared in
hooks.jsonhistory (git log -Scomes back empty for both), and the shippedsettings.system.jsontemplate carries no hooks block — so a fresh install gets no fire path for LoopDetector or DriftReminder at all. The consolidation's live registrations appear to have never been carried into the public install manifest.Two smaller HookSystem.md nits in the same area:
FormatGate.hook.ts, whichStopGates.hook.tsimports first in its gate chain (FormatGate's header describes it as OutputFormatGate's successor with teeth, 2026-07-11) — so the dispatched-file count is 9, not 8.ContextReduction.hook.sh).Possible resolutions (maintainer's call on intent)
PostToolObserver(PostToolUse catch-all) andDriftRemindertohooks.jsonso installs match HookSystem.md.Happy to PR either direction.
Context
Found while syncing
hooks/README.mdto registration truth (PR #1595, which documents the manifest as-is and stays neutral on this question).