@softspark/ai-toolkit 4.1.0 → 4.2.1

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.
@@ -1,8 +1,10 @@
1
1
  # GEO — Generative Engine Optimization
2
2
 
3
- Reference for `seo-validate` Category 6. Structuring content so AI answer engines (ChatGPT, Perplexity, Google AI Overviews, Bing Copilot, Claude) can extract, cite, and quote it accurately.
3
+ Reference for `seo-validate` Category 6. Structuring content so AI answer engines (ChatGPT, Perplexity, Google AI Overviews, Bing Copilot, Claude, Google AI Mode) can extract, cite, and quote it accurately.
4
4
 
5
- GEO is emerging practice, not a ranking algorithm with known penalties. **All findings in Category 6 are severity `INFO`** — guidance, not enforcement.
5
+ GEO patterns have measurable impact on AI citation probability. **Category 6 findings are `WARN` (chunk size, author quality, freshness) or `INFO` (hedging, frameworks, contrast, bio)** — guidance based on citation research, not penalty-causing.
6
+
7
+ See [ai-pipeline.md](ai-pipeline.md) for Google's 4-stage pipeline and 7 ranking signals. See [content-citability.md](content-citability.md) for chunk anatomy, semantic triples, and hedging patterns.
6
8
 
7
9
  ## Core Principles
8
10
 
@@ -224,17 +226,124 @@ These don't render content for crawlers at all. **Category 7 (rendering) superse
224
226
 
225
227
  ---
226
228
 
229
+ ## Chunk Architecture
230
+
231
+ Google's retrieval stage (Stage 2 of the pipeline — see [ai-pipeline.md](ai-pipeline.md)) splits content into chunks of ≤500 tokens (~375 words). AI does not read your article — it extracts one chunk and uses it as the answer. If the answer is distributed across multiple sections or buried after a long preamble, AI cannot assemble it.
232
+
233
+ **The 375-word rule:** Each H2 section should stay within ~375 words. If a section runs longer, add an H3 — each H3 becomes its own independent chunk candidate.
234
+
235
+ ### Anatomy of a citable chunk
236
+
237
+ ```
238
+ H2: [Question or keyword-rich heading]
239
+
240
+ ├── Direct answer — 2–3 sentences. Fact first. No preamble.
241
+
242
+ ├── Elaboration — data, context, nuance. 3–5 sentences.
243
+
244
+ ├── Visual element — list, table, or code block.
245
+
246
+ └── TL;DR (optional) — 1-sentence summary for long sections.
247
+ ```
248
+
249
+ ### Before / after
250
+
251
+ **Before (unchunkable):**
252
+ ```
253
+ H2: Choosing the Right Mattress
254
+
255
+ When you're looking for a new mattress, there are many factors to consider.
256
+ The market offers a wide variety of options, and it can be overwhelming...
257
+ [70 words of preamble]
258
+ Eventually, firmness is one of the most important factors...
259
+ ```
260
+ *AI extracts the preamble as the "answer" — zero information.*
261
+
262
+ **After (chunk-optimised):**
263
+ ```
264
+ H2: How to Choose Mattress Firmness by Body Weight
265
+
266
+ Match firmness to your weight: under 70 kg → H1–H2; 70–90 kg → H3; over 90 kg → H4.
267
+ Higher body weight needs firmer support to maintain spinal alignment.
268
+
269
+ | Weight | Firmness |
270
+ |-----------|-----------|
271
+ | < 70 kg | H1–H2 |
272
+ | 70–90 kg | H3 |
273
+ | > 90 kg | H4 |
274
+ ```
275
+ *AI extracts the first two sentences. Table is precision bonus.*
276
+
277
+ ---
278
+
279
+ ## Semantic Triples vs Marketing Prose
280
+
281
+ AI answer engines parse content as Subject → Predicate → Object triples. Marketing prose requires inference; triples require none — lower hallucination risk, higher citation frequency.
282
+
283
+ | Style | Example | AI extractable? |
284
+ |---|---|---|
285
+ | Marketing prose | "Our exceptional collection will enchant you with its elegance." | No — zero extractable facts |
286
+ | Semantic triples | "Firmness: H3. Dimensions: 160×200 cm. Ideal for: side sleepers, 70–90 kg. Not for: stomach sleepers." | Yes — 4 distinct facts |
287
+
288
+ Each triple answers a different AI sub-query. Six triples on a product page = six citation opportunities.
289
+
290
+ ---
291
+
292
+ ## Opinionated Content
293
+
294
+ AI skips hedged claims. "This may be a good choice for many people" cannot be used as an answer to "which mattress should I buy?" Google's Jetstream signal explicitly rewards declarative, opinionated content.
295
+
296
+ **Hedging to eliminate → replacement:**
297
+
298
+ | Hedging | Replacement |
299
+ |---|---|
300
+ | "may be a good choice" | "We recommend X for Y" |
301
+ | "worth considering" | "Our top pick for Z is X" |
302
+ | "for many people" | "for side sleepers weighing 70–90 kg" |
303
+ | "it depends" | "It depends on your weight: under 70 kg → H2, over 90 kg → H4" |
304
+
305
+ **Rule:** Every guide and product page must take a position. Recommendation + named persona + justification = citable.
306
+
307
+ ---
308
+
309
+ ## The 13-Week Freshness Rule
310
+
311
+ 50% of top AI-cited content was published or updated within the last 13 weeks (Blyskall, 40M AI Overviews results). After 13 weeks without a visible update, citation probability drops.
312
+
313
+ **Both signals required:**
314
+ 1. `dateModified` in JSON-LD — machine-readable freshness signal.
315
+ 2. Visible "Updated: [date]" near the byline — AI engines parse visible text; users trust visible dates.
316
+
317
+ JSON-LD alone is insufficient.
318
+
319
+ **Refresh strategy:**
320
+
321
+ | Action | Interval |
322
+ |---|---|
323
+ | Full content review + update | Every 12 weeks for top pillar pages |
324
+ | Date + minor fact refresh | Every 13 weeks for cluster articles |
325
+ | Add new FAQ or data point | On new data availability for product pages |
326
+
327
+ ---
328
+
227
329
  ## Checklist (Category 6 findings)
228
330
 
331
+ - [ ] Each H2 section is ≤375 words; sections exceeding this have an H3 sub-heading.
332
+ - [ ] First paragraph under each heading is ≤60 words before a concrete fact or recommendation.
333
+ - [ ] No hedging language ("may be", "worth considering", "for many") in recommendation contexts.
334
+ - [ ] At least one decision framework ("if X → choose Y") per guide or category page.
335
+ - [ ] At least one explicit contrast ("X vs Y", "unlike X") per comparison page.
336
+ - [ ] At least one negative definition ("not recommended for…") per product or category page.
337
+ - [ ] Author block: real name (not "Admin"), ≥30-word bio, `Person` schema with `sameAs`.
338
+ - [ ] `dateModified` in JSON-LD AND visible "Updated: [date]" text present.
229
339
  - [ ] FAQ-style content uses `FAQPage` schema.
230
340
  - [ ] Summary content uses `speakable` schema.
231
- - [ ] Paragraphs >400 words are broken up with sub-headings.
232
341
  - [ ] Citations use `<cite>` and author bylines.
233
342
  - [ ] Quoted content uses `<blockquote>`/`<q>` with `cite` attr.
234
343
  - [ ] How-to content uses `<ol>` + `HowTo` schema.
235
344
  - [ ] Comparative data uses `<table>` with proper headers.
236
345
  - [ ] Glossary content uses `<dl>`/`<dt>`/`<dd>`.
237
- - [ ] Semantic HTML (`<article>`, `<section>`, `<main>`, `<nav>`, `<aside>`) is used over `<div>`.
346
+ - [ ] Semantic HTML (`<article>`, `<section>`, `<main>`) used over `<div>`.
238
347
  - [ ] Critical content is NOT hidden behind tabs/accordions (except native `<details>`).
239
348
 
240
349
  ---
@@ -1,5 +1,5 @@
1
1
  {
2
- "last_run": "2026-05-06T08:17:20Z",
2
+ "last_run": "2026-05-12T10:01:38Z",
3
3
  "schema_version": 1,
4
4
  "tools": {
5
5
  "aider": {
@@ -24,10 +24,10 @@
24
24
  }
25
25
  },
26
26
  "augment": {
27
- "docs_hash": "ac138d99235e1f3e",
27
+ "docs_hash": "b746d5dbbc5a2936",
28
28
  "headings": [
29
29
  "Agent",
30
- "Code Completions",
30
+ "Chat",
31
31
  "Documentation Index",
32
32
  "Introduction",
33
33
  "\u200bAuggie CLI",
@@ -57,7 +57,7 @@
57
57
  }
58
58
  },
59
59
  "claude-code": {
60
- "docs_hash": "789113e1bc4cd34c",
60
+ "docs_hash": "9e0292a9f92392e0",
61
61
  "headings": [
62
62
  "Claude Code overview",
63
63
  "Documentation Index",
@@ -85,7 +85,7 @@
85
85
  "SessionEnd": false,
86
86
  "SessionStart": false,
87
87
  "Setup": true,
88
- "Stop": false,
88
+ "Stop": true,
89
89
  "StopFailure": false,
90
90
  "SubagentStart": false,
91
91
  "SubagentStop": false,
@@ -103,10 +103,10 @@
103
103
  "slash command": true,
104
104
  "sub-agent": true
105
105
  },
106
- "version": "2.1.131 (Claude Code)"
106
+ "version": "2.1.139 (Claude Code)"
107
107
  },
108
108
  "cline": {
109
- "docs_hash": "b4009dc8e6d40af9",
109
+ "docs_hash": "b59e8836b3217cdb",
110
110
  "headings": [
111
111
  "Cline CLI",
112
112
  "Cline Documentation",
@@ -137,7 +137,7 @@
137
137
  }
138
138
  },
139
139
  "codex-cli": {
140
- "docs_hash": "c6b51936294d38e7",
140
+ "docs_hash": "3f963da56d00add9",
141
141
  "headings": [
142
142
  "About",
143
143
  "Contributing",
@@ -156,7 +156,7 @@
156
156
  "Packages 0",
157
157
  "Provide feedback",
158
158
  "Quickstart",
159
- "Releases 765",
159
+ "Releases 784",
160
160
  "Repository files navigation",
161
161
  "Resources",
162
162
  "Saved searches",
@@ -186,10 +186,10 @@
186
186
  "mcp_servers": false,
187
187
  "sandbox": true
188
188
  },
189
- "version": "codex-cli 0.128.0"
189
+ "version": "codex-cli 0.130.0"
190
190
  },
191
191
  "cursor": {
192
- "docs_hash": "8ed1f5cf7441b6c0",
192
+ "docs_hash": "705adfd617433088",
193
193
  "headings": [],
194
194
  "markers": {
195
195
  ".cursor/rules": false,
@@ -205,7 +205,7 @@
205
205
  }
206
206
  },
207
207
  "gemini-cli": {
208
- "docs_hash": "21a2f14121ff27fa",
208
+ "docs_hash": "93694630a3d04327",
209
209
  "headings": [
210
210
  "Breadcrumbs",
211
211
  "Directory actions",
@@ -244,7 +244,7 @@
244
244
  }
245
245
  },
246
246
  "github-copilot": {
247
- "docs_hash": "99a5ab7bd5f7556f",
247
+ "docs_hash": "d9b9fcdfe3b67469",
248
248
  "headings": [
249
249
  "About Copilot auto model selection",
250
250
  "About Copilot integrations",
@@ -292,7 +292,7 @@
292
292
  }
293
293
  },
294
294
  "opencode": {
295
- "docs_hash": "fe845a4bffb6371b",
295
+ "docs_hash": "c1c8ba8f6b2e7ddf",
296
296
  "headings": [
297
297
  "Add features",
298
298
  "Ask questions",
@@ -353,7 +353,7 @@
353
353
  }
354
354
  },
355
355
  "windsurf": {
356
- "docs_hash": "9b2879646f041aea",
356
+ "docs_hash": "66295add1d0f0645",
357
357
  "headings": [
358
358
  "Advanced",
359
359
  "App Deploys",
@@ -3,9 +3,9 @@ title: "AI Toolkit - Architecture Overview"
3
3
  category: reference
4
4
  service: ai-toolkit
5
5
  tags: [architecture, overview, design, structure]
6
- version: "1.4.4"
6
+ version: "1.4.5"
7
7
  created: "2026-03-23"
8
- last_updated: "2026-04-15"
8
+ last_updated: "2026-05-12"
9
9
  description: "Architecture of ai-toolkit: directory layout, global install model, editor-aware MCP install, Codex translation layer, skill tiers, and integration with projects."
10
10
  ---
11
11
 
@@ -264,7 +264,7 @@ Agents (code-reviewer, debugger, devops-implementer, ...)
264
264
 
265
265
  ## Quality Hooks
266
266
 
267
- 21 entries across 12 lifecycle events. See [hooks-catalog.md](hooks-catalog.md) for full details.
267
+ 22 entries across 12 lifecycle events. See [hooks-catalog.md](hooks-catalog.md) for full details.
268
268
 
269
269
  | Hook | Trigger | Script | Action |
270
270
  |------|---------|--------|--------|
@@ -282,6 +282,7 @@ Agents (code-reviewer, debugger, devops-implementer, ...)
282
282
  | PostToolUse | After any tool | `governance-capture.sh` | Log security-sensitive operations |
283
283
  | Stop | After response | `quality-check.sh` | Multi-language lint |
284
284
  | Stop | After response | `save-session.sh` | Persist session context |
285
+ | Stop | Before final stop | `quality-gate.sh` | Block final response on lint/type errors |
285
286
  | TaskCompleted | Agent Teams: task done | `quality-gate.sh` | Block completion on errors |
286
287
  | TeammateIdle | Agent Teams: idle | *(inline)* | Completeness reminder |
287
288
  | SubagentStart | Subagent spawn | `subagent-start.sh` | Scope reminder for subagents |
@@ -3,9 +3,9 @@ title: "Hooks Catalog"
3
3
  category: reference
4
4
  service: ai-toolkit
5
5
  tags: [hooks, quality, safety, enforcement, settings.json]
6
- version: "1.5.0"
6
+ version: "1.5.1"
7
7
  created: "2026-03-27"
8
- last_updated: "2026-04-24"
8
+ last_updated: "2026-05-12"
9
9
  description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
10
10
  ---
11
11
 
@@ -13,7 +13,7 @@ description: "Complete reference of all ai-toolkit hooks: events, scripts, insta
13
13
 
14
14
  ## Overview
15
15
 
16
- ai-toolkit provides 21 global hook entries across 12 lifecycle events that enforce quality, safety, and workflow rules across all Claude Code sessions. Hooks are merged into `~/.claude/settings.json` on install, with logic in standalone scripts at `~/.softspark/ai-toolkit/hooks/`.
16
+ ai-toolkit provides 22 global hook entries across 12 lifecycle events that enforce quality, safety, and workflow rules across all Claude Code sessions. Hooks are merged into `~/.claude/settings.json` on install, with logic in standalone scripts at `~/.softspark/ai-toolkit/hooks/`.
17
17
 
18
18
  ## Supported Surface
19
19
 
@@ -164,6 +164,19 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
164
164
 
165
165
  Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
166
166
 
167
+ ### Stop (quality gate) — `quality-gate.sh`
168
+
169
+ | Field | Value |
170
+ |-------|-------|
171
+ | Event | `Stop` |
172
+ | Matcher | *(all)* |
173
+ | Script | `~/.softspark/ai-toolkit/hooks/quality-gate.sh` |
174
+ | Fires | Before Claude is allowed to finish a response |
175
+
176
+ **Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session.
177
+
178
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
179
+
167
180
  ### TaskCompleted — `quality-gate.sh`
168
181
 
169
182
  | Field | Value |
@@ -362,7 +375,7 @@ Set in `.claude/settings.local.json`:
362
375
  ├── PreToolUse → guard-destructive.sh, guard-path.sh, guard-config.sh, commit-quality.sh
363
376
  ├── UserPromptSubmit → user-prompt-submit.sh, track-usage.sh
364
377
  ├── PostToolUse → post-tool-use.sh, governance-capture.sh
365
- ├── Stop → quality-check.sh, save-session.sh
378
+ ├── Stop → quality-check.sh, save-session.sh, quality-gate.sh
366
379
  ├── TaskCompleted → quality-gate.sh
367
380
  ├── TeammateIdle → echo (inline)
368
381
  ├── SubagentStart → subagent-start.sh
@@ -4,7 +4,7 @@ category: reference
4
4
  service: ai-toolkit
5
5
  tags: [features, differentiators, constitution, hooks, security, tdd, memory]
6
6
  created: "2026-04-13"
7
- last_updated: "2026-04-13"
7
+ last_updated: "2026-05-12"
8
8
  description: "Detailed description of ai-toolkit's unique features: constitution enforcement, hooks system, security scanning, effort budgeting, quality gates, and more."
9
9
  ---
10
10
 
@@ -12,7 +12,7 @@ description: "Detailed description of ai-toolkit's unique features: constitution
12
12
 
13
13
  ## 1. Machine-Enforced Constitution
14
14
 
15
- Unlike other toolkits that put safety rules in documentation only, ai-toolkit enforces a 5-article constitution via `PreToolUse` hooks. The hook actually **blocks** execution of:
15
+ Unlike other toolkits that put safety rules in documentation only, ai-toolkit enforces a 6-article constitution via hooks. The hooks actually **block** execution of:
16
16
  - Mass deletion (`rm -rf`, `DROP TABLE`)
17
17
  - Blind overwrites of uncommitted work
18
18
  - Any action that could cause irreversible data loss
@@ -21,7 +21,7 @@ Unlike other toolkits that put safety rules in documentation only, ai-toolkit en
21
21
 
22
22
  Hook logic lives in `app/hooks/*.sh` — not inline JSON one-liners. Scripts are copied to `~/.softspark/ai-toolkit/hooks/` on install and referenced from `~/.claude/settings.json`. Easy to read, debug, and extend.
23
23
 
24
- **12 lifecycle events / 21 global hook entries:**
24
+ **12 lifecycle events / 22 global hook entries:**
25
25
 
26
26
  | Event | Script | Action |
27
27
  |-------|--------|--------|
@@ -39,6 +39,7 @@ Hook logic lives in `app/hooks/*.sh` — not inline JSON one-liners. Scripts are
39
39
  | PostToolUse | `governance-capture.sh` | Log security-sensitive operations to JSONL |
40
40
  | Stop | `quality-check.sh` | Multi-language lint (ruff/tsc/phpstan/dart/go) |
41
41
  | Stop | `save-session.sh` | Persist session context for cross-session continuity |
42
+ | Stop | `quality-gate.sh` | Block final response on lint/type errors |
42
43
  | TaskCompleted | `quality-gate.sh` | Block task completion on lint/type errors |
43
44
  | SubagentStart | `subagent-start.sh` | Narrow-scope reminder for spawned subagents |
44
45
  | SubagentStop | `subagent-stop.sh` | Completion checklist for subagent handoff |
package/llms-full.txt CHANGED
@@ -215,7 +215,7 @@
215
215
  - **search-specialist**: Information retrieval and search optimization specialist. Trigger words: search, query, semantic search, information retrieval, relevance, ranking, search optimization
216
216
  - **security-architect**: Proactive security design expert. Use for Threat Modeling, architecture security reviews, and designing secure systems (AuthN/AuthZ, Crypto).
217
217
  - **security-auditor**: Security expert. Use for OWASP Top 10, CVE analysis, security audits, penetration testing, vulnerability assessment, hardening. Triggers: security, owasp, cve, vulnerability, audit, hardening, penetration, pentest, injection test, api security.
218
- - **seo-specialist**: Search engine + generative engine optimization specialist. Trigger words: SEO, GEO, AEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org, llms.txt, ChatGPT visibility, Claude citation, Perplexity ranking, AI Overviews
218
+ - **seo-specialist**: Search engine + generative engine optimization specialist. Trigger words: SEO, GEO, AEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org, llms.txt, ChatGPT visibility, Claude citation, Perplexity ranking, AI Overviews, topical authority, chunk architecture, semantic triples, query fan out
219
219
  - **system-governor**: The Guardian of the Constitution. Validates all evolutionary changes and enforces immutable rules. Has VETO power.
220
220
  - **tech-lead**: Technical authority for code quality, architecture patterns, and stack decisions. Use for code reviews, technological disputes, and standards enforcement.
221
221
  - **technical-researcher**: Deep technical investigation and multi-source research synthesis specialist. Trigger words: technical research, feasibility study, root cause analysis, API investigation, compatibility research, comparison matrix, synthesize, aggregate, report, executive summary, gap analysis, findings, multi-source, cross-reference
@@ -6091,9 +6091,9 @@ title: "AI Toolkit - Architecture Overview"
6091
6091
  category: reference
6092
6092
  service: ai-toolkit
6093
6093
  tags: [architecture, overview, design, structure]
6094
- version: "1.4.4"
6094
+ version: "1.4.5"
6095
6095
  created: "2026-03-23"
6096
- last_updated: "2026-04-15"
6096
+ last_updated: "2026-05-12"
6097
6097
  description: "Architecture of ai-toolkit: directory layout, global install model, editor-aware MCP install, Codex translation layer, skill tiers, and integration with projects."
6098
6098
  ---
6099
6099
 
@@ -6352,7 +6352,7 @@ Agents (code-reviewer, debugger, devops-implementer, ...)
6352
6352
 
6353
6353
  ## Quality Hooks
6354
6354
 
6355
- 21 entries across 12 lifecycle events. See [hooks-catalog.md](hooks-catalog.md) for full details.
6355
+ 22 entries across 12 lifecycle events. See [hooks-catalog.md](hooks-catalog.md) for full details.
6356
6356
 
6357
6357
  | Hook | Trigger | Script | Action |
6358
6358
  |------|---------|--------|--------|
@@ -6370,6 +6370,7 @@ Agents (code-reviewer, debugger, devops-implementer, ...)
6370
6370
  | PostToolUse | After any tool | `governance-capture.sh` | Log security-sensitive operations |
6371
6371
  | Stop | After response | `quality-check.sh` | Multi-language lint |
6372
6372
  | Stop | After response | `save-session.sh` | Persist session context |
6373
+ | Stop | Before final stop | `quality-gate.sh` | Block final response on lint/type errors |
6373
6374
  | TaskCompleted | Agent Teams: task done | `quality-gate.sh` | Block completion on errors |
6374
6375
  | TeammateIdle | Agent Teams: idle | *(inline)* | Completeness reminder |
6375
6376
  | SubagentStart | Subagent spawn | `subagent-start.sh` | Scope reminder for subagents |
@@ -8757,9 +8758,9 @@ title: "Hooks Catalog"
8757
8758
  category: reference
8758
8759
  service: ai-toolkit
8759
8760
  tags: [hooks, quality, safety, enforcement, settings.json]
8760
- version: "1.5.0"
8761
+ version: "1.5.1"
8761
8762
  created: "2026-03-27"
8762
- last_updated: "2026-04-24"
8763
+ last_updated: "2026-05-12"
8763
8764
  description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
8764
8765
  ---
8765
8766
 
@@ -8767,7 +8768,7 @@ description: "Complete reference of all ai-toolkit hooks: events, scripts, insta
8767
8768
 
8768
8769
  ## Overview
8769
8770
 
8770
- ai-toolkit provides 21 global hook entries across 12 lifecycle events that enforce quality, safety, and workflow rules across all Claude Code sessions. Hooks are merged into `~/.claude/settings.json` on install, with logic in standalone scripts at `~/.softspark/ai-toolkit/hooks/`.
8771
+ ai-toolkit provides 22 global hook entries across 12 lifecycle events that enforce quality, safety, and workflow rules across all Claude Code sessions. Hooks are merged into `~/.claude/settings.json` on install, with logic in standalone scripts at `~/.softspark/ai-toolkit/hooks/`.
8771
8772
 
8772
8773
  ## Supported Surface
8773
8774
 
@@ -8918,6 +8919,19 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
8918
8919
 
8919
8920
  Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
8920
8921
 
8922
+ ### Stop (quality gate) — `quality-gate.sh`
8923
+
8924
+ | Field | Value |
8925
+ |-------|-------|
8926
+ | Event | `Stop` |
8927
+ | Matcher | *(all)* |
8928
+ | Script | `~/.softspark/ai-toolkit/hooks/quality-gate.sh` |
8929
+ | Fires | Before Claude is allowed to finish a response |
8930
+
8931
+ **Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session.
8932
+
8933
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
8934
+
8921
8935
  ### TaskCompleted — `quality-gate.sh`
8922
8936
 
8923
8937
  | Field | Value |
@@ -9116,7 +9130,7 @@ Set in `.claude/settings.local.json`:
9116
9130
  ├── PreToolUse → guard-destructive.sh, guard-path.sh, guard-config.sh, commit-quality.sh
9117
9131
  ├── UserPromptSubmit → user-prompt-submit.sh, track-usage.sh
9118
9132
  ├── PostToolUse → post-tool-use.sh, governance-capture.sh
9119
- ├── Stop → quality-check.sh, save-session.sh
9133
+ ├── Stop → quality-check.sh, save-session.sh, quality-gate.sh
9120
9134
  ├── TaskCompleted → quality-gate.sh
9121
9135
  ├── TeammateIdle → echo (inline)
9122
9136
  ├── SubagentStart → subagent-start.sh
@@ -11749,7 +11763,7 @@ category: reference
11749
11763
  service: ai-toolkit
11750
11764
  tags: [features, differentiators, constitution, hooks, security, tdd, memory]
11751
11765
  created: "2026-04-13"
11752
- last_updated: "2026-04-13"
11766
+ last_updated: "2026-05-12"
11753
11767
  description: "Detailed description of ai-toolkit's unique features: constitution enforcement, hooks system, security scanning, effort budgeting, quality gates, and more."
11754
11768
  ---
11755
11769
 
@@ -11757,7 +11771,7 @@ description: "Detailed description of ai-toolkit's unique features: constitution
11757
11771
 
11758
11772
  ## 1. Machine-Enforced Constitution
11759
11773
 
11760
- Unlike other toolkits that put safety rules in documentation only, ai-toolkit enforces a 5-article constitution via `PreToolUse` hooks. The hook actually **blocks** execution of:
11774
+ Unlike other toolkits that put safety rules in documentation only, ai-toolkit enforces a 6-article constitution via hooks. The hooks actually **block** execution of:
11761
11775
  - Mass deletion (`rm -rf`, `DROP TABLE`)
11762
11776
  - Blind overwrites of uncommitted work
11763
11777
  - Any action that could cause irreversible data loss
@@ -11766,7 +11780,7 @@ Unlike other toolkits that put safety rules in documentation only, ai-toolkit en
11766
11780
 
11767
11781
  Hook logic lives in `app/hooks/*.sh` — not inline JSON one-liners. Scripts are copied to `~/.softspark/ai-toolkit/hooks/` on install and referenced from `~/.claude/settings.json`. Easy to read, debug, and extend.
11768
11782
 
11769
- **12 lifecycle events / 21 global hook entries:**
11783
+ **12 lifecycle events / 22 global hook entries:**
11770
11784
 
11771
11785
  | Event | Script | Action |
11772
11786
  |-------|--------|--------|
@@ -11784,6 +11798,7 @@ Hook logic lives in `app/hooks/*.sh` — not inline JSON one-liners. Scripts are
11784
11798
  | PostToolUse | `governance-capture.sh` | Log security-sensitive operations to JSONL |
11785
11799
  | Stop | `quality-check.sh` | Multi-language lint (ruff/tsc/phpstan/dart/go) |
11786
11800
  | Stop | `save-session.sh` | Persist session context for cross-session continuity |
11801
+ | Stop | `quality-gate.sh` | Block final response on lint/type errors |
11787
11802
  | TaskCompleted | `quality-gate.sh` | Block task completion on lint/type errors |
11788
11803
  | SubagentStart | `subagent-start.sh` | Narrow-scope reminder for spawned subagents |
11789
11804
  | SubagentStop | `subagent-stop.sh` | Completion checklist for subagent handoff |
package/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.1.0",
2
+ "version": "4.2.1",
3
3
  "components": {
4
4
  "agents": {
5
5
  "description": "44 specialized agents (orchestrator, backend, frontend, security, devops, etc.)",
@@ -16,7 +16,7 @@
16
16
  "tags": ["core", "skills", "commands"]
17
17
  },
18
18
  "hooks": {
19
- "description": "21 global hook entries across 12 lifecycle events + 5 skill-scoped lifecycle hooks",
19
+ "description": "22 global hook entries across 12 lifecycle events + 5 skill-scoped lifecycle hooks",
20
20
  "path": "app/hooks.json + app/hooks/*.sh",
21
21
  "target": "~/.claude/settings.json (merge) + ~/.softspark/ai-toolkit/hooks/ (copy)",
22
22
  "type": "merge+copy",
@@ -30,7 +30,7 @@
30
30
  "tags": ["plugins", "packs", "experimental"]
31
31
  },
32
32
  "constitution": {
33
- "description": "5-article machine-enforced safety constitution",
33
+ "description": "6-article machine-enforced safety constitution",
34
34
  "path": "app/constitution.md",
35
35
  "target": ".claude/constitution.md",
36
36
  "type": "symlink",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softspark/ai-toolkit",
3
- "version": "4.1.0",
3
+ "version": "4.2.1",
4
4
  "description": "AI coding toolkit: 107 skills, 44 agents, 12-editor write-through (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo, Aider, Augment, Antigravity, Codex, opencode), machine-enforced safety constitution, SARIF audit, signed npm provenance.",
5
5
  "keywords": [
6
6
  "claude",
@@ -41,7 +41,7 @@
41
41
  "ai-toolkit": "bin/ai-toolkit.js"
42
42
  },
43
43
  "scripts": {
44
- "prepublishOnly": "npm run generate:all && python3 scripts/validate.py && npm test",
44
+ "prepublishOnly": "npm run generate:all && python3 scripts/validate.py --strict && npm test",
45
45
  "test": "bats tests/ --jobs 4 --no-parallelize-within-files",
46
46
  "validate": "python3 scripts/validate.py",
47
47
  "evaluate": "python3 scripts/evaluate_skills.py",
@@ -65,11 +65,49 @@ def _is_toolkit_entry(entry: dict) -> bool:
65
65
  return False
66
66
 
67
67
 
68
- def strip_toolkit(hooks: dict) -> dict:
69
- """Remove all entries tagged with _source == SOURCE_TAG."""
68
+ def _entry_signature(entry: dict) -> tuple:
69
+ """Return the behavior-defining parts of a hook entry.
70
+
71
+ Older ai-toolkit installs wrote hook entries without ``_source``. Matching
72
+ on the event, matcher, and handler payload lets current installs remove
73
+ those legacy duplicates while preserving unrelated user hooks.
74
+ """
75
+ handlers = []
76
+ for hook in entry.get("hooks", []):
77
+ if not isinstance(hook, dict):
78
+ handlers.append(hook)
79
+ continue
80
+ handlers.append(tuple(sorted(
81
+ (key, value)
82
+ for key, value in hook.items()
83
+ if key != "_source"
84
+ )))
85
+ return (entry.get("matcher", ""), tuple(handlers))
86
+
87
+
88
+ def strip_toolkit(hooks: dict, toolkit_hooks: dict | None = None) -> dict:
89
+ """Remove entries tagged with ai-toolkit or matching legacy toolkit hooks."""
90
+ legacy_signatures: dict[str, set[tuple]] = {}
91
+ if toolkit_hooks:
92
+ for event, entries in toolkit_hooks.items():
93
+ legacy_signatures[event] = {
94
+ _entry_signature(entry)
95
+ for entry in entries
96
+ if isinstance(entry, dict)
97
+ }
98
+
70
99
  result = {}
71
100
  for event, entries in hooks.items():
72
- filtered = [e for e in entries if not _is_toolkit_entry(e)]
101
+ signatures = legacy_signatures.get(event, set())
102
+ filtered = [
103
+ e
104
+ for e in entries
105
+ if not _is_toolkit_entry(e)
106
+ and not (
107
+ isinstance(e, dict)
108
+ and _entry_signature(e) in signatures
109
+ )
110
+ ]
73
111
  if filtered:
74
112
  result[event] = filtered
75
113
  return result
@@ -85,7 +123,7 @@ def merge(toolkit_hooks: dict, target_hooks: dict) -> dict:
85
123
  Returns:
86
124
  Merged hooks dictionary with old toolkit entries replaced by new ones.
87
125
  """
88
- merged = strip_toolkit(target_hooks)
126
+ merged = strip_toolkit(target_hooks, toolkit_hooks)
89
127
  for event, entries in toolkit_hooks.items():
90
128
  if event not in merged:
91
129
  merged[event] = []
@@ -9,6 +9,9 @@ Stdlib-only — no external dependencies.
9
9
  from __future__ import annotations
10
10
 
11
11
  import ssl
12
+ import json
13
+ import os
14
+ from pathlib import Path
12
15
  import urllib.error
13
16
  import urllib.request
14
17
 
@@ -34,6 +37,13 @@ def fetch_url(url: str) -> bytes:
34
37
  f"Only HTTPS URLs are supported (got: {url.split('://')[0]}://)"
35
38
  )
36
39
 
40
+ fixture_map = os.environ.get("AI_TOOLKIT_TEST_URL_FIXTURE_MAP")
41
+ if fixture_map and os.environ.get("AI_TOOLKIT_TEST_MODE") == "1":
42
+ fixtures = json.loads(fixture_map)
43
+ fixture_path = fixtures.get(url)
44
+ if fixture_path:
45
+ return Path(fixture_path).read_bytes()
46
+
37
47
  ctx = ssl.create_default_context()
38
48
  with urllib.request.urlopen(url, timeout=_FETCH_TIMEOUT, context=ctx) as resp:
39
49
  data = resp.read(_FETCH_MAX_BYTES)