Resolves v2.3.0 dogfood collision: skill-factory produced a
specialized hooks-pattern.md draft that would have overwritten the
generic seed. Qualified slugs let one feature host multiple named
patterns at different abstraction levels.
Slug convention: <cc_feature>[-<qualifier>]-<layer>.md. Unqualified =
canonical baseline. Qualified = sub-pattern (e.g., hooks-observability-
pattern.md) that does not displace the baseline.
Changes:
- SKILL.md: slug convention section, coverage-table qualified column,
matcher logic for N patterns per feature, modification rules cover
qualified-vs-canonical choice and collision handling.
- feature-matcher: catalog map is cc_feature -> {layer -> [skills]};
selection rules (baseline by default, qualified when justified,
multi-skill when non-overlapping); supporting_skill accepts list.
- gap-identifier: adds pattern_count[cc_feature] to coverage audit.
- architecture-critic: supporting-skill verification — every cited
skill name must exist in the catalog (blocker severity).
- First qualified skill: hooks-observability-pattern.md (promoted from
.drafts/, source ai-psychosis/README.md, ngram-overlap 0.01).
- Version bump 2.3.0 -> 2.3.1 across plugin.json, badges, table, root
CLAUDE.md, CHANGELOG.
Non-breaking: existing unqualified slugs keep working, no cc_feature
taxonomy changes, hallucination gate unchanged.
50 lines
3.3 KiB
Markdown
50 lines
3.3 KiB
Markdown
---
|
|
name: hooks-observability-pattern
|
|
description: Observe user-interaction patterns across session lifecycle hooks and emit cooldown-gated nudges
|
|
layer: pattern
|
|
cc_feature: hooks
|
|
source: ../../../../ai-psychosis/README.md
|
|
concept: progressive alerts via lifecycle hooks
|
|
last_verified: 2026-04-18
|
|
ngram_overlap_score: 0.01
|
|
review_status: approved
|
|
---
|
|
|
|
# Hooks — Progressive-Alert Observability Pattern
|
|
|
|
## Use this when
|
|
|
|
- Measure behaviour the model itself cannot see: cadence, duration, repetition, time-of-day.
|
|
- Surface soft nudges rather than hard blocks — the operator keeps the final call.
|
|
- Separate "what happened" (metrics) from "what was said" (prompt text) so no conversation content touches disk.
|
|
|
|
## Shape
|
|
|
|
- Wire four lifecycle events: a start handler for baseline counters, a prompt handler for language-category flags, a tool handler for cadence and burst detection, and an end handler for totals and state cleanup.
|
|
- Keep per-session counters in a tiny JSON file under the plugin data dir; keep aggregate events in an append-only JSONL log for later reporting.
|
|
- Gate every nudge behind two things: a threshold (hard or soft) and a cooldown window, so repeat alerts do not spam the transcript.
|
|
- Deliver alerts as `additionalContext` injection, never as a tool block — the goal is awareness, not control.
|
|
|
|
## Forces
|
|
|
|
- **Privacy vs. signal.** Richer signal wants more content logged; the user wants none. Resolve by computing boolean flags in-memory and discarding the raw text before the handler returns.
|
|
- **Latency budget.** Handlers fire on every prompt and every tool call. Stay well under 100 ms per invocation; append-only JSONL is sub-millisecond and safe.
|
|
- **Portability.** Hooks that assume a shell, `jq`, or npm dependencies break on half the operator fleet. Stick to Node stdlib so the same script runs on macOS, Linux, and Windows.
|
|
- **Instruction layer alone is not enough.** Behavioural rules in a skill file shape tone but cannot measure duration or frequency. Layer the hook observability on top of the skill — each compensates for the other.
|
|
|
|
## Gotchas
|
|
|
|
- A handler that crashes blocks the turn. Catch everything, log, and exit zero by default.
|
|
- Cooldowns must be per-category, not global, or the most-triggered alert silences the rarer, more informative ones.
|
|
- Late-night and rapid-fire thresholds are legitimate signals but also easy to over-tune; start with generous bands and tighten only with data.
|
|
- `additionalContext` from an end-of-session handler is discarded — inject alerts on start, prompt, or tool events where the model will actually see them.
|
|
|
|
## Anti-patterns
|
|
|
|
- Storing prompt text or tool arguments "just for debugging" — once it is on disk, the privacy guarantee is gone.
|
|
- Treating every elevated metric as an intervention. If the hook starts blocking, the operator works around it and loses the awareness benefit.
|
|
- Hardcoding thresholds into the handler. Pull them from a single config so future tuning does not require a rewrite of four scripts.
|
|
|
|
## Decision quick-check
|
|
|
|
Reach for this pattern when you need visibility into *how* the user is interacting, not *what* they are saying, and when the response should be a gentle nudge rather than a gate. Otherwise use a PreToolUse denylist (hard limit) or a skill-only instruction layer (style, not cadence).
|