@softspark/ai-toolkit 4.20.0 → 4.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,174 @@
1
+ # Accessibility Scanner Categories
2
+
3
+ ### Category 1: Semantic Structure & Landmarks
4
+
5
+ WCAG 1.3.1 (Info and Relationships), 2.4.1 (Bypass Blocks), 2.4.6 (Headings and Labels), 3.1.1 (Language of Page), 3.1.2 (Language of Parts).
6
+
7
+ | Pattern | Severity | Confidence | Description |
8
+ |---------|----------|------------|-------------|
9
+ | `<html>` missing `lang` attribute | HIGH | definitive | WCAG 3.1.1 |
10
+ | Mixed-language content without `<span lang="...">` wrapper (heuristic: non-Latin characters in otherwise-Latin content) | WARN | heuristic | WCAG 3.1.2 |
11
+ | Page/route component with >1 `<h1>` | WARN | heuristic | WCAG 1.3.1 |
12
+ | Heading level skip (h1 → h3 without h2) | WARN | heuristic | WCAG 1.3.1 |
13
+ | No landmark roles / semantic elements (`<main>`, `<nav>`, `<header>`, `<footer>`) | WARN | heuristic | WCAG 1.3.1, 2.4.1 |
14
+ | `role="presentation"` / `role="none"` on semantic element | WARN | definitive | Strips meaning; misuse of ARIA |
15
+ | Multiple `<main>` per page | HIGH | definitive | WCAG 1.3.1 — only one `<main>` allowed |
16
+
17
+ ### Category 2: Text Alternatives & Non-Text Content
18
+
19
+ WCAG 1.1.1 (Non-text Content).
20
+
21
+ | Pattern | Severity | Confidence | Description |
22
+ |---------|----------|------------|-------------|
23
+ | `<img>` without `alt` attribute | HIGH | definitive | WCAG 1.1.1 — required even if empty |
24
+ | `<img alt="">` on informational image (heuristic: image inside `<article>`, `<figure>`, or with adjacent caption) | WARN | heuristic | Empty alt only for decorative |
25
+ | `<img alt="image">` / `<img alt="photo">` / `<img alt="picture">` (redundant/meaningless) | WARN | definitive | Alt should describe content |
26
+ | `<svg>` without `<title>` + `role="img"` + `aria-label`, used in interactive context | WARN | heuristic | Inline SVG needs alternative |
27
+ | Icon font (`<i class="fa-...">`, `<span class="material-icons">`) without `aria-label` or text alternative | WARN | definitive | WCAG 1.1.1 |
28
+ | `<img>` used for text content (heuristic: `alt` contains a full sentence like "Click here to...") | WARN | heuristic | WCAG 1.4.5 Images of Text |
29
+ | Complex image (`<img>` with `src` matching `chart|graph|diagram|infographic`) without long description (`aria-describedby` or `longdesc` or linked description) | WARN | heuristic | WCAG 1.1.1 for complex content |
30
+
31
+ ### Category 3: Keyboard & Focus
32
+
33
+ WCAG 2.1.1 (Keyboard), 2.1.2 (No Keyboard Trap), 2.4.3 (Focus Order), 2.4.7 (Focus Visible).
34
+
35
+ | Pattern | Severity | Confidence | Description |
36
+ |---------|----------|------------|-------------|
37
+ | `tabindex` value >0 (positive) | HIGH | definitive | WCAG 2.4.3 — breaks natural tab order |
38
+ | `tabindex="-1"` on natively interactive element (`<button>`, `<a href>`, `<input>`, etc.) | WARN | definitive | Removes from tab order |
39
+ | `outline: none` or `outline: 0` on focusable selector without `:focus-visible` replacement | HIGH | definitive | WCAG 2.4.7 |
40
+ | `onClick` / `onKeyDown` handler on `<div>` / `<span>` without `role="button"` + `tabindex="0"` + keydown handler for Enter/Space | HIGH | heuristic | WCAG 2.1.1 — not keyboard-accessible |
41
+ | No skip link (`<a href="#main">`, `<a href="#content">`) on page with navigation | WARN | heuristic | WCAG 2.4.1 Bypass Blocks |
42
+ | Potential keyboard trap: `event.preventDefault()` / `event.stopPropagation()` in keydown handler on modal/dialog without Escape handling | WARN | heuristic | WCAG 2.1.2 |
43
+ | Custom dropdown / combobox without `aria-expanded` + `aria-haspopup` + keyboard handlers | WARN | heuristic | WAI-ARIA Authoring Practices |
44
+ | `autofocus` on page load on non-critical input (distracts keyboard users, moves focus unexpectedly) | WARN | definitive | Confuses assistive tech |
45
+ | `contenteditable="true"` without `aria-label` / `aria-labelledby` | WARN | definitive | WCAG 4.1.2 |
46
+
47
+ ### Category 4: Color, Contrast & Visual Cues
48
+
49
+ WCAG 1.4.1 (Use of Color), 1.4.3 (Contrast Minimum), 1.4.11 (Non-text Contrast).
50
+
51
+ **Static analysis limitation**: actual contrast ratios depend on the CSS cascade, custom properties, theme switching, and background images. The skill flags patterns where contrast is AT RISK; pair with runtime tools (axe-core, Lighthouse) for definitive measurement.
52
+
53
+ | Pattern | Severity | Confidence | Description |
54
+ |---------|----------|------------|-------------|
55
+ | Hardcoded foreground+background color pairs in CSS where computed contrast is <4.5:1 (normal) or <3:1 (large text) | WARN | heuristic | WCAG 1.4.3 — verify at runtime |
56
+ | Link inside body text without underline/border AND only `color` distinguishing it | WARN | heuristic | WCAG 1.4.1 — color-only signalling |
57
+ | Error/required field indicated only by red color (no icon, text, or shape) | WARN | heuristic | WCAG 1.4.1 |
58
+ | Required form field marked only with `*` character without `aria-required="true"` + text explanation | WARN | definitive | WCAG 1.4.1 + 3.3.2 |
59
+ | CSS uses `color: red`/`color: green` as sole signal (success vs error) | WARN | heuristic | WCAG 1.4.1 |
60
+ | Focus indicator with <3:1 contrast against background (heuristic from color values) | WARN | heuristic | WCAG 1.4.11 |
61
+ | Button/input border color with <3:1 contrast against adjacent color | WARN | heuristic | WCAG 1.4.11 |
62
+ | CSS `text-shadow`/`opacity` on body text reducing effective contrast | INFO | heuristic | May affect 1.4.3 |
63
+
64
+ ### Category 5: Forms, Labels & Errors
65
+
66
+ WCAG 1.3.5 (Identify Input Purpose), 3.3.1 (Error Identification), 3.3.2 (Labels or Instructions), 3.3.3 (Error Suggestion), 4.1.2 (Name, Role, Value).
67
+
68
+ | Pattern | Severity | Confidence | Description |
69
+ |---------|----------|------------|-------------|
70
+ | `<input>` / `<select>` / `<textarea>` without `<label for="...">` AND without `aria-label` / `aria-labelledby` | HIGH | heuristic | WCAG 3.3.2, 4.1.2 |
71
+ | `<label>` without `for` attribute (implicit association only works if input is a child) | WARN | definitive | WCAG 3.3.2 |
72
+ | `<input type="email"/tel/name/password/address">` without `autocomplete` attribute | WARN | definitive | WCAG 1.3.5 |
73
+ | Missing `autocomplete="one-time-code"` on OTP input with `inputmode="numeric"` | INFO | definitive | Improves user experience |
74
+ | Radio / checkbox group without `<fieldset>` + `<legend>` | WARN | heuristic | WCAG 1.3.1 |
75
+ | Error messages displayed visually but not linked via `aria-describedby` to the input | WARN | heuristic | WCAG 3.3.1 |
76
+ | `required` attribute without accompanying `aria-required="true"` (belt-and-suspenders for assistive tech consistency) | INFO | definitive | WCAG 4.1.2 (modern SR handle `required` but legacy may not) |
77
+ | Error uses `role="alert"` without being updated dynamically (static alert on page load) | INFO | heuristic | WCAG 4.1.3 |
78
+ | Placeholder used as label (no visible label, only `placeholder`) | WARN | heuristic | WCAG 3.3.2 — placeholder disappears on focus |
79
+ | `<input type="email">` without `inputmode="email"` (mobile UX) | INFO | definitive | EN 301 549 mobile |
80
+
81
+ ### Category 6: Media (Audio, Video, Embeds)
82
+
83
+ WCAG 1.2.1–1.2.5 (Captions, audio description, sign language), 1.4.2 (Audio Control).
84
+
85
+ **EAA is specifically strict about media** — video without captions is a common legal-risk finding.
86
+
87
+ | Pattern | Severity | Confidence | Description |
88
+ |---------|----------|------------|-------------|
89
+ | `<video>` without `<track kind="captions">` child (or `<track kind="subtitles">` for foreign-language) | HIGH | definitive | WCAG 1.2.2 — EAA legal risk |
90
+ | `<video>` without transcript link or `<track kind="descriptions">` | WARN | heuristic | WCAG 1.2.3 / 1.2.5 |
91
+ | `<audio>` without transcript link or `<track kind="captions">` | HIGH | definitive | WCAG 1.2.1 |
92
+ | `<video autoplay>` without `muted` | HIGH | definitive | WCAG 1.4.2 — auto-playing audio |
93
+ | `<video autoplay loop>` running >5 seconds without pause control | WARN | heuristic | WCAG 1.4.2, 2.2.2 |
94
+ | YouTube/Vimeo embed URL without `cc_load_policy=1` or equivalent CC parameter | INFO | definitive | Platform-dependent captioning |
95
+ | YouTube embed via `<iframe src="https://www.youtube.com/embed/...">` without accessibility enhancements | INFO | definitive | Note: platform controls most a11y |
96
+ | Live media without real-time caption indication | WARN | heuristic | WCAG 1.2.4 |
97
+ | Background video (hero section) without pause button in DOM | WARN | heuristic | WCAG 2.2.2 |
98
+
99
+ ### Category 7: ARIA, Live Regions & Dynamic Content
100
+
101
+ WCAG 4.1.2 (Name, Role, Value), 4.1.3 (Status Messages).
102
+
103
+ | Pattern | Severity | Confidence | Description |
104
+ |---------|----------|------------|-------------|
105
+ | `aria-hidden="true"` on focusable element | HIGH | definitive | Creates orphaned focus — serious a11y bug |
106
+ | `role="button"` on native `<button>` (redundant ARIA) | WARN | definitive | ARIA Authoring: avoid redundant roles |
107
+ | `role="link"` on `<a href>` / `role="heading"` on `<h1–h6>` (redundant ARIA) | WARN | definitive | Same |
108
+ | Conflicting roles (`<button role="link">`, `<a role="button">`) | WARN | definitive | WAI-ARIA — wrong role |
109
+ | Custom toggle (disclosure, menu, accordion) without `aria-expanded` + `aria-controls` | WARN | heuristic | WAI-ARIA |
110
+ | `aria-labelledby` referencing non-existent ID | HIGH | heuristic | Broken reference |
111
+ | `aria-describedby` referencing non-existent ID | HIGH | heuristic | Broken reference |
112
+ | `aria-live` region without `role="status"` / `role="alert"` AND async updates in component (heuristic) | WARN | heuristic | WCAG 4.1.3 |
113
+ | Toast/notification component without `role="status"` or `role="alert"` | WARN | heuristic | WCAG 4.1.3 |
114
+ | Modal / dialog without `role="dialog"` + `aria-modal="true"` + focus trap | WARN | heuristic | WAI-ARIA Authoring Practices |
115
+ | Tabs without proper roles (`role="tablist"` + `role="tab"` + `role="tabpanel"`) | WARN | heuristic | WAI-ARIA Authoring Practices |
116
+
117
+ ### Category 8: Motion, Target Size, Mobile & EAA Docs
118
+
119
+ #### 8a. Motion & Animation
120
+
121
+ WCAG 2.2.2 (Pause, Stop, Hide), 2.3.3 (Animation from Interactions — AAA but EAA-recommended).
122
+
123
+ | Pattern | Severity | Confidence | Description |
124
+ |---------|----------|------------|-------------|
125
+ | CSS animation / transition / transform without matching `@media (prefers-reduced-motion: reduce)` override | WARN | heuristic | WCAG 2.3.3 |
126
+ | JS animation library (GSAP, framer-motion, anime.js) without `matchMedia('(prefers-reduced-motion: reduce)')` check | WARN | heuristic | WCAG 2.3.3 |
127
+ | Parallax scrolling without opt-out | WARN | heuristic | WCAG 2.3.3 |
128
+ | Infinite animation (CSS `animation: name infinite`) on content element without pause control | WARN | heuristic | WCAG 2.2.2 |
129
+ | `<marquee>` / `<blink>` (deprecated) | HIGH | definitive | WCAG 2.2.2 |
130
+
131
+ #### 8b. Target Size (WCAG 2.2 Minimum AA 2.5.8 + EN 301 549)
132
+
133
+ | Pattern | Severity | Confidence | Description |
134
+ |---------|----------|------------|-------------|
135
+ | Interactive target with declared size <24×24 px (heuristic from CSS: `width`/`height`/`padding` on buttons/links/inputs) | WARN | heuristic | WCAG 2.2 2.5.8 / EN 301 549 |
136
+ | Touch-target spacing <8 px between adjacent interactive elements | INFO | heuristic | Best practice |
137
+
138
+ #### 8c. Viewport & Zoom
139
+
140
+ | Pattern | Severity | Confidence | Description |
141
+ |---------|----------|------------|-------------|
142
+ | `<meta name="viewport">` containing `user-scalable=no` / `user-scalable=0` | HIGH | definitive | WCAG 1.4.4 — blocks zoom |
143
+ | `<meta name="viewport">` with `maximum-scale=1` / `maximum-scale=1.0` | HIGH | definitive | WCAG 1.4.4 |
144
+ | Content rendered via `<img>` for text (text-as-image) | WARN | heuristic | WCAG 1.4.5 |
145
+
146
+ #### 8d. Mobile (React Native + Flutter)
147
+
148
+ EN 301 549 mobile chapter. Critical for EAA scope since consumer apps are in-scope.
149
+
150
+ | Pattern | Severity | Confidence | Description |
151
+ |---------|----------|------------|-------------|
152
+ | **React Native**: `<TouchableOpacity>` / `<TouchableHighlight>` / `<Pressable>` without `accessibilityLabel` | HIGH | definitive | EN 301 549 mobile |
153
+ | **React Native**: `<Image>` without `accessibilityLabel` or `accessible={false}` | WARN | heuristic | EN 301 549 |
154
+ | **React Native**: Missing `accessibilityRole` on custom components that behave as buttons/links | WARN | heuristic | EN 301 549 |
155
+ | **React Native**: `Alert.alert` for error flow without `AccessibilityInfo.announceForAccessibility` fallback | INFO | heuristic | — |
156
+ | **Flutter**: Interactive widget (`GestureDetector`, `InkWell`, `TextButton`, `IconButton`) without `Semantics()` wrapper or `semanticLabel` parameter | HIGH | definitive | EN 301 549 mobile |
157
+ | **Flutter**: `Image()` / `Image.asset()` / `Image.network()` without `semanticLabel` (or `excludeFromSemantics: true` for decorative) | WARN | definitive | EN 301 549 |
158
+ | **Flutter**: Missing `ExcludeSemantics` / `MergeSemantics` where child semantics conflict | INFO | heuristic | Semantics tree cleanup |
159
+
160
+ #### 8e. EAA Accessibility Documentation
161
+
162
+ **Activated by `--standard eaa`.** EAA Article 14 + member-state transpositions require consumer-facing services to publish an accessibility statement. Missing statement = HIGH legal finding.
163
+
164
+ | Pattern | Severity | Confidence | Description |
165
+ |---------|----------|------------|-------------|
166
+ | No route at any of: `/accessibility`, `/accessibility-statement`, `/a11y`, `/dostepnosc` (PL), `/barrierefreiheit` (DE), `/declaration-accessibilite` (FR), `/declaración-accesibilidad` (ES), `/dichiarazione-accessibilita` (IT), `/toegankelijkheidsverklaring` (NL) | HIGH | heuristic | EAA Article 14 |
167
+ | Footer / sitemap lacks link to accessibility statement | HIGH | heuristic | EAA visibility requirement |
168
+ | Accessibility statement present but missing required elements: (a) conformance level (WCAG/EN 301 549), (b) list of non-conformant content, (c) feedback mechanism, (d) enforcement procedure link | WARN | heuristic | Member-state template requirement |
169
+ | No contact mechanism (email / form) for accessibility feedback referenced in statement | WARN | heuristic | EAA Article 14 |
170
+ | `robots.txt` disallows `/accessibility*` path (accidentally blocks statement from crawlers + assistive tech) | WARN | definitive | Discoverability |
171
+
172
+ See: [eaa-compliance.md](eaa-compliance.md) for directive text, member-state deadlines, statement templates.
173
+
174
+ ---
@@ -0,0 +1,174 @@
1
+ ---
2
+ name: brainstorm
3
+ description: "Pre-artifact conversation that prices the zero option and can end in 'do not build this'. Triggers: brainstorm, should we build, is this worth it, explore idea, thinking out loud, half-formed idea."
4
+ user-invocable: true
5
+ effort: high
6
+ argument-hint: "[the idea, problem, or half-formed thought]"
7
+ allowed-tools: Read, Grep, Glob, Bash, Agent
8
+ ---
9
+
10
+ # Brainstorm
11
+
12
+ $ARGUMENTS
13
+
14
+ The conversation that happens *before* an artifact exists. Every other planning
15
+ skill here produces something — a PRD, a plan, issues, a design. This one is
16
+ allowed to produce nothing, and that is its point.
17
+
18
+ ## The zero option is a real candidate
19
+
20
+ Price "build nothing" against the proposal properly. Not as a strawman, not as a
21
+ sentence acknowledged and moved past — as a genuine option with its own costs:
22
+
23
+ - what breaks or stays broken if nobody does this
24
+ - who currently absorbs that, and how much it costs them
25
+ - how long the problem has existed without being fixed, and what that says about it
26
+ - what the codebase carries forever once this exists: another surface, another
27
+ migration path, another thing that has to keep working
28
+
29
+ If the zero option wins, say so and stop. **Do not invent a deliverable to justify
30
+ the conversation.** A brainstorm that ends in "this is not worth building, and
31
+ here is what it would have cost" has done its job.
32
+
33
+ ## Steps
34
+
35
+ ### Step 1: Understand before proposing
36
+
37
+ Explore the actual codebase before shaping anything. Read what exists, grep for
38
+ prior attempts, check whether the problem is already solved somewhere.
39
+
40
+ Ask what the user is trying to achieve, not what they want built. The stated
41
+ request is a proposed solution; the problem behind it is what matters. Keep
42
+ asking until you can state the problem without naming the solution.
43
+
44
+ ### Step 2: Shape the options
45
+
46
+ Produce at least three genuinely different approaches, one of which is always
47
+ "do nothing / do it manually / wait". Different means different in kind, not
48
+ three variants of the same shape.
49
+
50
+ For each: what it costs, what it forecloses, what has to stay true for it to keep
51
+ working.
52
+
53
+ ### Step 3: Resolve the unknowns
54
+
55
+ List what nobody in the conversation actually knows. For each, decide whether it
56
+ can be resolved now (read the code, check the data, run something) or whether it
57
+ stays open and becomes a risk the next stage inherits.
58
+
59
+ Resolve what is cheap to resolve. An unknown carried into a PRD becomes an Open
60
+ Question; an unknown carried past a PRD becomes a bug.
61
+
62
+ ### Step 4: Challenge the conclusion
63
+
64
+ Before routing anywhere, spawn a **separate** agent to attack the conclusion. Not
65
+ you re-reading your own reasoning — a different context that did not fall in love
66
+ with the idea.
67
+
68
+ ```
69
+ Use the Agent tool with subagent_type: general-purpose.
70
+
71
+ Your job is to break the conclusion below, not to improve it. Assume it is wrong
72
+ and find out where. If you cannot break it, say what specifically held.
73
+
74
+ Conclusion reached: <one paragraph>
75
+ Options rejected, with reasons: <list — the zero option is always one of them>
76
+ Unknowns still open: <list>
77
+
78
+ Work through these in order:
79
+
80
+ 1. Restate the problem without naming any solution. If you cannot, the problem
81
+ was never separated from the proposal and everything below is downstream of
82
+ that.
83
+ 2. Who pays for the problem today, how often, and how much? If nobody can be
84
+ named, the cost is assumed rather than observed.
85
+ 3. The problem has existed until now without this being built. What changed —
86
+ or is the trigger just that someone thought of it?
87
+ 4. Take the zero-option reasoning and argue the opposite side as well as you can.
88
+ If that argument is stronger than the one that won, the zero option was
89
+ dismissed rather than priced.
90
+ 5. What does the codebase carry permanently once this exists? Count the surface,
91
+ the migration path, the thing that must keep working.
92
+ 6. Name the single assumption that, if false, wastes the most work — and the
93
+ cheapest thing that would prove it false today.
94
+ 7. Hand the brief to someone who was not here. What do they ask first?
95
+
96
+ Report as: BLOCKER (the conclusion or the chosen next step does not survive),
97
+ CONCERN (holds, but on an assumption worth naming), HOLDS (what you tried to
98
+ break and could not).
99
+
100
+ Write plainly and skip the closing summary. Do not soften findings to be
101
+ agreeable — agreement you did not test is worth nothing here. A first pass over
102
+ a fresh idea that produces no BLOCKER and no CONCERN almost always means the
103
+ attack was shallow; go back to question 4.
104
+ ```
105
+
106
+ Any BLOCKER goes back to Step 2 or Step 3. Do not route past one.
107
+
108
+ ### Step 5: Take an exit ramp
109
+
110
+ Pick exactly one and say which, in the user's words, before invoking anything.
111
+
112
+ | # | When | Next |
113
+ |---|------|------|
114
+ | 1 | Nothing worth building, or the question is answered | **stop** — no artifact, no handoff |
115
+ | 2 | Worth doing, not now | write a brief to `kb/planning/`, stop |
116
+ | 3 | Feature, unknowns resolved | `/write-a-prd` |
117
+ | 4 | Feature, user wants to co-design | `/design-an-interface`, then `/write-a-prd` |
118
+ | 5 | Small and obvious, no spec needed | `/tdd` or `/fix` directly |
119
+ | 6 | Already tracked somewhere | point at the existing issue or task, stop |
120
+
121
+ Ramp 1 and ramp 6 are the two most likely to be correct and the two most likely to
122
+ be skipped. Check both before considering the others.
123
+
124
+ ## Rules
125
+
126
+ - **MUST** price the zero option explicitly and state why it lost, before any ramp
127
+ other than 1 is taken
128
+ - **MUST** spawn the challenger as a separate agent — self-review at Step 4 does
129
+ not count and is the failure mode this skill exists to prevent
130
+ - **NEVER** invoke a downstream skill without naming the ramp and the reason first
131
+ - **NEVER** produce a PRD, plan, or issue from inside this skill — it routes, it
132
+ does not build
133
+ - **CRITICAL**: ending at ramp 1 is a success, and is reported as one, not as an
134
+ apology
135
+ - **MANDATORY**: at least one of the three options in Step 2 is always the zero
136
+ option
137
+
138
+ ## Gotchas
139
+
140
+ - The challenger only works from a **separate** context. Re-reading your own
141
+ reasoning in the same conversation reproduces the same blind spots and returns
142
+ OK on everything, which reads as validation and is nothing of the kind.
143
+ - A challenger that never returns BLOCKER or CONCERN is broken, not agreeable. If
144
+ several runs come back clean, check that the conclusion, the rejected options
145
+ and the open unknowns are actually being passed in — an attacker given nothing
146
+ to attack reports that everything holds.
147
+ - "The user asked for it" is not the problem statement. Users arrive with a
148
+ solution already chosen; Step 1 is not finished until the problem stands without
149
+ it.
150
+ - Sunk conversation is not evidence. Forty minutes of good discussion does not make
151
+ the idea worth building, and the pull toward a handoff gets stronger the longer
152
+ the conversation ran. That pull is exactly what ramp 1 resists.
153
+ - Ramp 6 loses to novelty. Searching the tracker feels like admitting the
154
+ conversation was wasted, so it gets skipped — do it early, in Step 1.
155
+ - This skill costs roughly double a plain planning session, because of the
156
+ challenger. That is only worth paying if ramp 1 or ramp 6 sometimes wins. If
157
+ every run of this skill routes to `/write-a-prd`, stop using it — it has become
158
+ ceremony.
159
+
160
+ ## When NOT to Use
161
+
162
+ - The decision is already made and you want it executed — use `/plan` or `/write-a-prd`
163
+ - A concrete plan exists and needs stress-testing — use `/grill-me`
164
+ - An architectural choice needs several expert perspectives — use `/council`
165
+ - A bug needs a root cause — use `/debug` or `/triage-issue`
166
+ - The change is one obvious line — just make it; a brainstorm about a typo is the
167
+ same waste as a PRD about one
168
+
169
+ ## Related Skills
170
+
171
+ - Chose to build it? → `/write-a-prd` for the requirements, then `/prd-to-plan`
172
+ - Need to compare interface shapes first? → `/design-an-interface`
173
+ - Want the plan attacked instead of the idea? → `/grill-me`
174
+ - Want four expert lenses on a decision? → `/council`
@@ -82,6 +82,7 @@ Use `ci-cd-patterns` skill for pipeline templates and best practices.
82
82
  - **NEVER** commit generated CI configs that embed hardcoded secrets or tokens
83
83
  - **CRITICAL**: preserve existing job names and triggers unless the user explicitly asks for a restructure
84
84
  - **MANDATORY**: every generated pipeline must include lint + test stages at minimum
85
+ - **MUST** collect every failing job before diagnosing — do not stop at the first red check. A pipeline usually breaks in more than one place, and reporting only the first one costs a full cycle per remaining failure
85
86
 
86
87
  ## Gotchas
87
88
 
@@ -25,7 +25,7 @@ Pipe error output through the error parser for structured diagnosis:
25
25
 
26
26
  ```bash
27
27
  # Pipe from failing command
28
- your_command 2>&1 | python3 "$(dirname "$0")/scripts/error-parser.py"
28
+ your_command 2>&1 | python3 ${CLAUDE_SKILL_DIR}/scripts/error-parser.py
29
29
 
30
30
  # Or from a log file
31
31
  cat /var/log/app/error.log | python3 scripts/error-parser.py
@@ -197,6 +197,7 @@ Report consensus when done.
197
197
  - **NEVER** apply fixes without first reproducing the symptom
198
198
  - **CRITICAL**: trace from symptom to root cause — do not stop at the first plausible explanation
199
199
  - **MANDATORY**: if the bug is intermittent, log enough state to reproduce it deterministically before fixing
200
+ - **MUST** finish collecting evidence (logs, health, recent diff, error-parser output) before forming the hypothesis — an investigation that halts at the first error found reports what the user already saw and misses the one they did not
200
201
 
201
202
  ## Gotchas
202
203
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: documentation-standards
3
- description: "KB conventions: YAML frontmatter, 5-category taxonomy (reference/howto/procedures/troubleshooting/best-practices). Triggers: kb/, SOP, runbook, howto, frontmatter, knowledge base."
3
+ description: "KB conventions: YAML frontmatter, 8-category taxonomy (reference/howto/procedures/troubleshooting/best-practices/decisions/runbooks/planning). Triggers: kb/, SOP, runbook, howto, frontmatter, knowledge base."
4
4
  effort: medium
5
5
  user-invocable: false
6
6
  allowed-tools: Read
@@ -27,7 +27,19 @@ version: "1.0.0" # optional — semver
27
27
  ---
28
28
  ```
29
29
 
30
- **All 7 fields above are REQUIRED.** Documents without valid frontmatter **fail `validate.sh` and block CI**.
30
+ **All 7 fields above are REQUIRED.** Documents without valid frontmatter **fail
31
+ `scripts/validate.py` and block CI**.
32
+
33
+ ### `section`: a legacy alias, not a second field
34
+
35
+ Older documents and the `kb-migration` SOP write `section:` where this
36
+ specification writes `category:`. Both names are read in the wild, so a document
37
+ may carry both — and when it does **they must hold the same value**. A document
38
+ filed as `category: reference` and `section: howto` is indexed twice, found
39
+ once, and the reader gets whichever the index ranked higher.
40
+
41
+ New documents should write `category:`. `section:` is accepted, never required,
42
+ and never authoritative on its own.
31
43
 
32
44
  ## Category Taxonomy
33
45
 
@@ -35,11 +47,17 @@ version: "1.0.0" # optional — semver
35
47
  |----------|-----------|---------|----------|
36
48
  | `reference` | `kb/reference/` | Technical specifications, catalogs, architecture notes, API docs | `agents-catalog.md`, `architecture-overview.md` |
37
49
  | `howto` | `kb/howto/` | Step-by-step task guides | `use-corrective-rag.md`, `configure-mcp-server.md` |
38
- | `procedures` | `kb/procedures/` | SOPs, runbooks, operational processes | `maintenance-sop.md`, `incident-response.md` |
50
+ | `procedures` | `kb/procedures/` | SOPs a person follows: release, migration, review | `maintenance-sop.md`, `sop-release.md` |
39
51
  | `troubleshooting` | `kb/troubleshooting/` | Problem resolution, debugging guides | `database-connection-issues.md` |
40
52
  | `best-practices` | `kb/best-practices/` | Guidelines, recommendations, standards | `security-checklist.md` |
53
+ | `decisions` | `kb/decisions/` | Architecture decision records and design rationale | `adr-004-kb-migration.md` |
54
+ | `runbooks` | `kb/runbooks/` | Procedures run against a live system, usually under pressure | `deployment.md`, `incident-response.md` |
55
+ | `planning` | `kb/planning/` | Roadmaps, PRDs, work not yet done | `q3-roadmap.md` |
41
56
 
42
- **Rule:** The `category:` frontmatter field MUST match the directory the file lives in.
57
+ **Rule:** A document filed under one of the directories above MUST declare that
58
+ category. The rule is scoped to those directories deliberately: `kb/history/`
59
+ and similar are lifecycle locations rather than types, and a finished plan filed
60
+ under `history/completed/` is still a `planning` document.
43
61
 
44
62
  ## Naming Conventions
45
63
 
@@ -178,7 +196,9 @@ scripts/validate.py
178
196
  # Checks: required fields present, category is valid, tags non-empty
179
197
  ```
180
198
 
181
- Valid categories: `reference`, `howto`, `procedures`, `troubleshooting`, `best-practices`, `planning`.
199
+ Valid categories are the eight in the table above. `scripts/validate.py` holds
200
+ the same set in `VALID_KB_CATEGORIES`; the two are the same list in two places
201
+ and a change belongs in both.
182
202
 
183
203
  ## Anti-Patterns
184
204
 
@@ -26,7 +26,7 @@ Before entering the fix loop, classify errors to prioritize auto-fixable ones:
26
26
 
27
27
  ```bash
28
28
  # Pipe lint or test output
29
- ruff check . 2>&1 | python3 "$(dirname "$0")/scripts/error-classifier.py"
29
+ ruff check . 2>&1 | python3 ${CLAUDE_SKILL_DIR}/scripts/error-classifier.py
30
30
  mypy src/ 2>&1 | python3 scripts/error-classifier.py
31
31
  npx eslint . 2>&1 | python3 scripts/error-classifier.py
32
32
  ```