feat(ultraplan-local): v2.3.1 — qualified slug convention for cc-architect-catalog
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.
This commit is contained in:
parent
bba72c8f06
commit
4bbd17cbfa
11 changed files with 232 additions and 38 deletions
|
|
@ -83,32 +83,70 @@ skill-factory output will start as `pending` (channel 2) or
|
|||
If a future skill covers a feature not in this list, add the row above
|
||||
and surface the extension in the relevant CHANGELOG entry.
|
||||
|
||||
## Slug convention
|
||||
|
||||
Skill filenames follow this pattern:
|
||||
|
||||
```
|
||||
<cc_feature>[-<qualifier>]-<layer>.md
|
||||
```
|
||||
|
||||
- **Unqualified slug** (`<feature>-<layer>.md`) — the baseline/canonical
|
||||
entry for that (feature, layer) pair. One per pair. Example:
|
||||
`hooks-pattern.md` = generic hook shapes and pitfalls.
|
||||
- **Qualified slug** (`<feature>-<qualifier>-<layer>.md`) — a
|
||||
specialized variant covering one specific sub-pattern or use-case.
|
||||
Zero-or-more per pair. Example: `hooks-observability-pattern.md` =
|
||||
progressive-alert observability pattern specifically.
|
||||
|
||||
Qualifiers exist because one CC feature can support multiple
|
||||
non-overlapping patterns at different abstraction levels. Forcing
|
||||
everything into a single `<feature>-<layer>.md` either bloats the
|
||||
canonical entry or loses useful specialization. Qualified slugs let the
|
||||
catalog grow with concrete, named patterns without displacing the
|
||||
baseline.
|
||||
|
||||
`feature-matcher` treats all skills with the same `cc_feature` + `layer`
|
||||
as candidates and picks the most relevant to the brief (or proposes
|
||||
several if they cover different aspects). See "How `feature-matcher`
|
||||
uses this file" below.
|
||||
|
||||
## Current seed coverage (v2.3.0 — see .drafts/ for skill-factory output)
|
||||
|
||||
| Feature | reference | pattern | decision |
|
||||
|---------|-----------|---------|----------|
|
||||
| hooks | hooks-reference | hooks-pattern | — |
|
||||
| subagents | subagents-reference | subagents-pattern | — |
|
||||
| skills | skills-reference | — | — |
|
||||
| output-styles | output-styles-reference | — | — |
|
||||
| mcp | mcp-reference | — | — |
|
||||
| plan-mode | plan-mode-reference | — | — |
|
||||
| worktrees | worktrees-reference | — | — |
|
||||
| background-agents | background-agents-reference | — | — |
|
||||
| Feature | reference | pattern | qualified patterns | decision |
|
||||
|---------|-----------|---------|--------------------|----------|
|
||||
| hooks | hooks-reference | hooks-pattern | hooks-observability-pattern | — |
|
||||
| subagents | subagents-reference | subagents-pattern | — | — |
|
||||
| skills | skills-reference | — | — | — |
|
||||
| output-styles | output-styles-reference | — | — | — |
|
||||
| mcp | mcp-reference | — | — | — |
|
||||
| plan-mode | plan-mode-reference | — | — | — |
|
||||
| worktrees | worktrees-reference | — | — | — |
|
||||
| background-agents | background-agents-reference | — | — | — |
|
||||
|
||||
Total: 10 seed skills, 8 features, 2 layers. Decision-layer is
|
||||
Total: 11 seed skills, 8 features, 2 layers. Decision-layer is
|
||||
intentionally empty — decisions cross features and require broader
|
||||
synthesis than a single seed pass can provide. Skill-factory populates
|
||||
decision-layer later.
|
||||
|
||||
## How `feature-matcher` uses this file
|
||||
|
||||
1. Read this file to learn the `cc_feature` taxonomy.
|
||||
1. Read this file to learn the `cc_feature` taxonomy and slug convention.
|
||||
2. Glob the directory for `*.md` files (excluding SKILL.md).
|
||||
3. Parse each skill's frontmatter.
|
||||
4. For each feature mentioned in the brief or research, match against
|
||||
`cc_feature` field. Prefer `pattern` over `reference` when both exist
|
||||
(pattern is richer).
|
||||
`cc_feature` field. Build the candidate set per feature, grouped by
|
||||
layer. Selection rules:
|
||||
- **Layer preference:** prefer `pattern` over `reference` when both
|
||||
exist (pattern is richer).
|
||||
- **Multiple patterns per feature:** when two or more pattern-layer
|
||||
skills share the same `cc_feature`, read each `description` and
|
||||
pick the one(s) most relevant to the brief. If two cover
|
||||
non-overlapping aspects that both apply, propose both with clear
|
||||
rationale. Prefer the unqualified baseline (`<feature>-pattern.md`)
|
||||
when the brief does not specifically justify a qualified variant.
|
||||
- **Be explicit:** name the chosen skill in `supporting_skill` so
|
||||
`architecture-critic` can verify the match.
|
||||
5. When no skill exists for a mentioned feature, fall back to the
|
||||
hardcoded minimum-list inside the `feature-matcher` prompt and mark
|
||||
the gap in stats (`fallback_used: true`).
|
||||
|
|
@ -132,9 +170,24 @@ decision-layer later.
|
|||
|
||||
## Modification rules
|
||||
|
||||
- Adding a new skill: create `<feature>-<layer>.md` with the frontmatter
|
||||
above and bump the coverage table in this file.
|
||||
- Renaming `cc_feature` values: update both this file AND every skill
|
||||
using the old value in the same commit.
|
||||
- Removing a skill: document in CHANGELOG under the version that drops
|
||||
it.
|
||||
- **Adding a canonical skill:** create `<feature>-<layer>.md` with the
|
||||
frontmatter contract above. Bump the coverage table in this file.
|
||||
- **Adding a qualified pattern skill:** create
|
||||
`<feature>-<qualifier>-<layer>.md` when the new pattern covers a
|
||||
distinct sub-case that does not belong in the unqualified baseline.
|
||||
The qualifier MUST be kebab-case and descriptive (e.g.,
|
||||
`observability`, `migration`, `multi-tenant`). Add it to the
|
||||
"qualified patterns" column in the coverage table.
|
||||
- **Choosing qualified vs. canonical:** if no unqualified skill exists
|
||||
yet for a `(feature, layer)` pair, the new skill SHOULD be the
|
||||
unqualified baseline — don't ship a qualified skill without a
|
||||
canonical one, because `feature-matcher` prefers baseline when the
|
||||
brief has no specific justification for a variant.
|
||||
- **Renaming `cc_feature` values:** update both this file AND every
|
||||
skill using the old value in the same commit.
|
||||
- **Removing a skill:** document in CHANGELOG under the version that
|
||||
drops it.
|
||||
- **Slug collision:** two skills with the same slug are a hard error.
|
||||
Skill-factory (`/ultra-skill-author-local`) must refuse to promote a
|
||||
draft that would overwrite an approved skill. Collision is resolved
|
||||
either by qualifying the new slug or by revising the baseline.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
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).
|
||||
Loading…
Add table
Add a link
Reference in a new issue