@softspark/ai-toolkit 4.4.1 → 4.5.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.
- package/CHANGELOG.md +44 -0
- package/README.md +28 -28
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/ARCHITECTURE.md +1 -1
- package/app/hooks/_profile-check.sh +17 -0
- package/app/hooks/guard-destructive.sh +19 -1
- package/app/hooks/loop-guard.sh +59 -0
- package/app/hooks/session-start.sh +4 -2
- package/app/hooks.json +10 -0
- package/app/plugins/memory-pack/README.md +2 -2
- package/app/plugins/memory-pack/scripts/strip_private.py +31 -4
- package/app/skills/hook-creator/SKILL.md +1 -0
- package/app/skills/instinct-review/SKILL.md +10 -10
- package/app/skills/skill-audit/SKILL.md +10 -0
- package/app/skills/verification-before-completion/SKILL.md +19 -0
- package/benchmarks/ecosystem-doctor-snapshot.json +27 -15
- package/kb/reference/hooks-catalog.md +22 -3
- package/kb/reference/mcp-editor-compatibility.md +1 -1
- package/kb/reference/supported-tools-registry.md +3 -3
- package/llms-full.txt +68 -17
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/audit_skills.py +82 -2
- package/scripts/doctor.py +51 -0
- package/scripts/ecosystem_tools.json +9 -1
- package/scripts/generate_codex_hooks.py +5 -4
- package/scripts/validate.py +84 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"last_run": "2026-05-
|
|
2
|
+
"last_run": "2026-05-30T19:51:17Z",
|
|
3
3
|
"schema_version": 1,
|
|
4
4
|
"tools": {
|
|
5
5
|
"aider": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"augment": {
|
|
27
|
-
"docs_hash": "
|
|
27
|
+
"docs_hash": "46ef1d20d537234f",
|
|
28
28
|
"headings": [
|
|
29
29
|
"Admin",
|
|
30
30
|
"Auggie CLI",
|
|
@@ -65,11 +65,15 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"claude-code": {
|
|
68
|
-
"docs_hash": "
|
|
68
|
+
"docs_hash": "b2ee6850b58cee40",
|
|
69
69
|
"headings": [
|
|
70
|
+
"Core concepts",
|
|
70
71
|
"Documentation Index",
|
|
72
|
+
"Getting started",
|
|
71
73
|
"On this page",
|
|
72
74
|
"Overview",
|
|
75
|
+
"Platforms and integrations",
|
|
76
|
+
"Use Claude Code",
|
|
73
77
|
"\u200bGet started",
|
|
74
78
|
"\u200bNext steps",
|
|
75
79
|
"\u200bUse Claude Code everywhere",
|
|
@@ -83,11 +87,14 @@
|
|
|
83
87
|
"FileChanged": false,
|
|
84
88
|
"InstructionsLoaded": false,
|
|
85
89
|
"MCP server": true,
|
|
90
|
+
"MessageDisplay": false,
|
|
86
91
|
"Notification": true,
|
|
87
92
|
"PermissionDenied": false,
|
|
88
93
|
"PermissionRequest": false,
|
|
89
94
|
"PostCompact": false,
|
|
95
|
+
"PostToolBatch": false,
|
|
90
96
|
"PostToolUse": true,
|
|
97
|
+
"PostToolUseFailure": false,
|
|
91
98
|
"PreCompact": false,
|
|
92
99
|
"PreToolUse": true,
|
|
93
100
|
"SKILL.md": true,
|
|
@@ -101,6 +108,7 @@
|
|
|
101
108
|
"TaskCompleted": false,
|
|
102
109
|
"TaskCreated": false,
|
|
103
110
|
"TeammateIdle": false,
|
|
111
|
+
"UserPromptExpansion": false,
|
|
104
112
|
"UserPromptSubmit": false,
|
|
105
113
|
"WorktreeCreate": false,
|
|
106
114
|
"WorktreeRemove": false,
|
|
@@ -112,10 +120,10 @@
|
|
|
112
120
|
"slash command": true,
|
|
113
121
|
"sub-agent": true
|
|
114
122
|
},
|
|
115
|
-
"version": "2.1.
|
|
123
|
+
"version": "2.1.158 (Claude Code)"
|
|
116
124
|
},
|
|
117
125
|
"cline": {
|
|
118
|
-
"docs_hash": "
|
|
126
|
+
"docs_hash": "9ec25e5132332d2f",
|
|
119
127
|
"headings": [
|
|
120
128
|
"API Reference",
|
|
121
129
|
"Best Practices",
|
|
@@ -156,7 +164,7 @@
|
|
|
156
164
|
}
|
|
157
165
|
},
|
|
158
166
|
"codex-cli": {
|
|
159
|
-
"docs_hash": "
|
|
167
|
+
"docs_hash": "f7a6a5144e0f61a2",
|
|
160
168
|
"headings": [
|
|
161
169
|
"About",
|
|
162
170
|
"Contributing",
|
|
@@ -175,7 +183,7 @@
|
|
|
175
183
|
"Packages 0",
|
|
176
184
|
"Provide feedback",
|
|
177
185
|
"Quickstart",
|
|
178
|
-
"Releases
|
|
186
|
+
"Releases 804",
|
|
179
187
|
"Repository files navigation",
|
|
180
188
|
"Resources",
|
|
181
189
|
"Saved searches",
|
|
@@ -193,10 +201,14 @@
|
|
|
193
201
|
"AGENTS.md": true,
|
|
194
202
|
"config.toml": false,
|
|
195
203
|
"hook event: PermissionRequest": false,
|
|
204
|
+
"hook event: PostCompact": false,
|
|
196
205
|
"hook event: PostToolUse": false,
|
|
206
|
+
"hook event: PreCompact": false,
|
|
197
207
|
"hook event: PreToolUse": false,
|
|
198
208
|
"hook event: SessionStart": false,
|
|
199
209
|
"hook event: Stop": false,
|
|
210
|
+
"hook event: SubagentStart": false,
|
|
211
|
+
"hook event: SubagentStop": false,
|
|
200
212
|
"hook event: UserPromptSubmit": false,
|
|
201
213
|
"hook handler: agent": false,
|
|
202
214
|
"hook handler: command": false,
|
|
@@ -205,10 +217,10 @@
|
|
|
205
217
|
"mcp_servers": false,
|
|
206
218
|
"sandbox": true
|
|
207
219
|
},
|
|
208
|
-
"version": "codex-cli 0.
|
|
220
|
+
"version": "codex-cli 0.134.0"
|
|
209
221
|
},
|
|
210
222
|
"cursor": {
|
|
211
|
-
"docs_hash": "
|
|
223
|
+
"docs_hash": "6aa8a8d7cc046f13",
|
|
212
224
|
"headings": [],
|
|
213
225
|
"markers": {
|
|
214
226
|
".cursor/rules": false,
|
|
@@ -224,7 +236,7 @@
|
|
|
224
236
|
}
|
|
225
237
|
},
|
|
226
238
|
"gemini-cli": {
|
|
227
|
-
"docs_hash": "
|
|
239
|
+
"docs_hash": "5569709cc2e463a8",
|
|
228
240
|
"headings": [
|
|
229
241
|
"Breadcrumbs",
|
|
230
242
|
"Directory actions",
|
|
@@ -263,16 +275,16 @@
|
|
|
263
275
|
}
|
|
264
276
|
},
|
|
265
277
|
"github-copilot": {
|
|
266
|
-
"docs_hash": "
|
|
278
|
+
"docs_hash": "56ac2d5768f930b5",
|
|
267
279
|
"headings": [
|
|
268
280
|
"About Copilot auto model selection",
|
|
269
281
|
"About Copilot integrations",
|
|
270
282
|
"About agent management",
|
|
271
283
|
"About agent skills",
|
|
272
284
|
"About billing for GitHub Copilot in organizations and enterprises",
|
|
273
|
-
"About billing for individual GitHub Copilot plans",
|
|
274
285
|
"About custom agents",
|
|
275
286
|
"About customizing GitHub Copilot responses",
|
|
287
|
+
"About enterprise accounts for Copilot Business",
|
|
276
288
|
"Articles",
|
|
277
289
|
"Did you find what you needed?",
|
|
278
290
|
"GitHub Copilot",
|
|
@@ -295,7 +307,7 @@
|
|
|
295
307
|
}
|
|
296
308
|
},
|
|
297
309
|
"google-antigravity": {
|
|
298
|
-
"docs_hash": "
|
|
310
|
+
"docs_hash": "f933b31ac7414c29",
|
|
299
311
|
"headings": [],
|
|
300
312
|
"markers": {
|
|
301
313
|
"AGENTS.md": false,
|
|
@@ -311,7 +323,7 @@
|
|
|
311
323
|
}
|
|
312
324
|
},
|
|
313
325
|
"opencode": {
|
|
314
|
-
"docs_hash": "
|
|
326
|
+
"docs_hash": "fe7f7590e4553574",
|
|
315
327
|
"headings": [
|
|
316
328
|
"Add features",
|
|
317
329
|
"Ask questions",
|
|
@@ -371,7 +383,7 @@
|
|
|
371
383
|
}
|
|
372
384
|
},
|
|
373
385
|
"windsurf": {
|
|
374
|
-
"docs_hash": "
|
|
386
|
+
"docs_hash": "a30041baf564742f",
|
|
375
387
|
"headings": [
|
|
376
388
|
"Accounts",
|
|
377
389
|
"Advanced",
|
|
@@ -3,7 +3,7 @@ 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.
|
|
6
|
+
version: "1.5.7"
|
|
7
7
|
created: "2026-03-27"
|
|
8
8
|
last_updated: "2026-05-25"
|
|
9
9
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
@@ -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
|
|
16
|
+
ai-toolkit provides 29 global hook entries across 14 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
|
|
|
@@ -85,6 +85,10 @@ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
|
|
|
85
85
|
- `git push --force`
|
|
86
86
|
- `chmod -R 777`
|
|
87
87
|
|
|
88
|
+
**Exemptions (avoid false positives):**
|
|
89
|
+
- `git push --force-with-lease` / `--force-if-includes` — the safe force-push variants are allowed.
|
|
90
|
+
- A single, non-chained `echo`/`printf`/`git commit`/`git tag` carrying a destructive token as *data* (e.g. a commit message mentioning `DROP TABLE`) is allowed. Chained commands (`&&`, `;`, `|`) are still inspected in full.
|
|
91
|
+
|
|
88
92
|
### PreToolUse (file ops) — `guard-path.sh`
|
|
89
93
|
|
|
90
94
|
| Field | Value |
|
|
@@ -403,6 +407,19 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
|
|
|
403
407
|
|
|
404
408
|
**Overrides:** `CLAUDE_SKIP_COHESION=1` (one-off), `CLAUDE_HOOK_BOOTSTRAP=1` (when editing the hook itself). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
405
409
|
|
|
410
|
+
### PostToolUse (loop guard) — `loop-guard.sh`
|
|
411
|
+
|
|
412
|
+
| Field | Value |
|
|
413
|
+
|-------|-------|
|
|
414
|
+
| Event | `PostToolUse` |
|
|
415
|
+
| Matcher | `Bash\|Edit\|MultiEdit\|Write` |
|
|
416
|
+
| Script | `~/.softspark/ai-toolkit/hooks/loop-guard.sh` |
|
|
417
|
+
| Fires | After every Bash command or file edit |
|
|
418
|
+
|
|
419
|
+
**Action:** Advisory only, never blocks. Hashes a `tool|identity` signature of each action (command for Bash; file path + new content for edits) and keeps the last `AI_TOOLKIT_LOOP_WINDOW` (default 6) hashes per session. When the same signature repeats `AI_TOOLKIT_LOOP_THRESHOLD` times (default 3) it emits a `PostToolUse` `additionalContext` advisory telling Claude to reassess instead of retrying. Catches successful-but-identical loops that the `/repeat` circuit breaker (which only counts failures) does not. Edits track content, so normal iterative editing of one file does not trip it. Only short hashes are stored — never raw payloads.
|
|
420
|
+
|
|
421
|
+
**Tunables:** `AI_TOOLKIT_LOOP_WINDOW`, `AI_TOOLKIT_LOOP_THRESHOLD`. Skipped when `TOOLKIT_HOOK_PROFILE=minimal`; honours `AI_TOOLKIT_DISABLED_HOOKS`.
|
|
422
|
+
|
|
406
423
|
### PostToolUse (search-first tracker) — `search-tracker.sh`
|
|
407
424
|
|
|
408
425
|
| Field | Value |
|
|
@@ -480,6 +497,8 @@ Set in `.claude/settings.local.json`:
|
|
|
480
497
|
| `standard` | All hooks (default) |
|
|
481
498
|
| `strict` | Standard + mypy --strict on task completion |
|
|
482
499
|
|
|
500
|
+
**Disabling individual hooks:** set `AI_TOOLKIT_DISABLED_HOOKS` to a comma-separated list of hook names (with or without `.sh`), e.g. `{ "env": { "AI_TOOLKIT_DISABLED_HOOKS": "loop-guard,quality-check" } }`. Listed hooks become no-ops. This covers profile-gated hooks only; the safety guards (`guard-destructive`/`guard-path`/`guard-config`) intentionally cannot be env-disabled — remove them deliberately with `ai-toolkit remove-hook`.
|
|
501
|
+
|
|
483
502
|
Non-blocking informational context is silent in plain-text mode by default while
|
|
484
503
|
side effects and blocking decisions still run. Set `AI_TOOLKIT_HOOK_VERBOSE=1`
|
|
485
504
|
only when debugging hook context locally. `AI_TOOLKIT_HOOK_QUIET=1` keeps hook
|
|
@@ -561,7 +580,7 @@ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
|
|
|
561
580
|
|
|
562
581
|
**Hook script not found:**
|
|
563
582
|
```bash
|
|
564
|
-
ls ~/.softspark/ai-toolkit/hooks/ # should list
|
|
583
|
+
ls ~/.softspark/ai-toolkit/hooks/ # should list 28 .sh files (plus _profile-check.sh + _locate-toolkit.sh + _hook-io.sh + _search-capability.sh helpers + test-cohesion-map.json)
|
|
565
584
|
ai-toolkit update # re-copies scripts
|
|
566
585
|
```
|
|
567
586
|
|
|
@@ -5,7 +5,7 @@ service: ai-toolkit
|
|
|
5
5
|
tags: [mcp, editors, compatibility, codex, cursor]
|
|
6
6
|
version: "1.1.0"
|
|
7
7
|
created: "2026-04-12"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-05-30"
|
|
9
9
|
description: "Official MCP support matrix and native config targets for editors supported by ai-toolkit."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ service: ai-toolkit
|
|
|
5
5
|
tags: [editors, platforms, generators, integration, ecosystem]
|
|
6
6
|
version: "1.3.0"
|
|
7
7
|
created: "2026-04-23"
|
|
8
|
-
last_updated: "2026-05-
|
|
8
|
+
last_updated: "2026-05-30"
|
|
9
9
|
description: "Human-readable view of scripts/ecosystem_tools.json — the canonical list of tools ai-toolkit integrates with (Claude Code + 11 editors), their documentation URLs, config paths, our generators, and tracked capability markers."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -30,7 +30,7 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
30
30
|
| Release notes | https://github.com/anthropics/claude-code/releases |
|
|
31
31
|
| Config paths | `~/.claude/settings.json`, `.claude/settings.local.json`, `CLAUDE.md`, `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `~/.claude/themes/*.json` (v2.1.118+) |
|
|
32
32
|
| Our generators | — (Claude Code is the primary target; toolkit content ships directly as `.md` files and `settings.json` merges) |
|
|
33
|
-
| Tracked hook events | Core: `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Notification`. Tool: `PreToolUse`, `PostToolUse`. Turn: `Stop`, `StopFailure`. Subagent: `SubagentStart`, `SubagentStop`. Compaction: `PreCompact`, `PostCompact`. Permissions: `PermissionRequest`, `PermissionDenied`. Elicitation: `Elicitation`, `ElicitationResult`. Teams: `TaskCreated`, `TaskCompleted`, `TeammateIdle`. Worktrees/env: `WorktreeCreate`, `WorktreeRemove`, `CwdChanged`, `FileChanged`, `ConfigChange`. Setup: `Setup`, `InstructionsLoaded` |
|
|
33
|
+
| Tracked hook events | Core: `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Notification`, `MessageDisplay`. Tool: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PostToolBatch`. Turn: `Stop`, `StopFailure`, `UserPromptExpansion`. Subagent: `SubagentStart`, `SubagentStop`. Compaction: `PreCompact`, `PostCompact`. Permissions: `PermissionRequest`, `PermissionDenied`. Elicitation: `Elicitation`, `ElicitationResult`. Teams: `TaskCreated`, `TaskCompleted`, `TeammateIdle`. Worktrees/env: `WorktreeCreate`, `WorktreeRemove`, `CwdChanged`, `FileChanged`, `ConfigChange`. Setup: `Setup`, `InstructionsLoaded` |
|
|
34
34
|
| Tracked handler types | `command`, `prompt`, `agent`, `mcp_tool` |
|
|
35
35
|
| Other capabilities | slash commands, MCP server/client, sub-agent, output style, `SKILL.md` (≥500 lines warn) |
|
|
36
36
|
| Version probe | `claude --version` |
|
|
@@ -163,7 +163,7 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
163
163
|
| Release notes | https://github.com/openai/codex/releases |
|
|
164
164
|
| Config paths | `AGENTS.md`, `.agents/rules/*.md`, `.agents/skills/*/SKILL.md`, `.codex/hooks.json`, `~/.codex/config.toml` |
|
|
165
165
|
| Our generators | `scripts/generate_codex.py`, `scripts/generate_codex_rules.py`, `scripts/generate_codex_hooks.py`, `scripts/generate_codex_skills.py` (opt-in via `--codex-skills`) |
|
|
166
|
-
| Tracked hook events | `PreToolUse`, `PostToolUse`, `SessionStart`, `UserPromptSubmit`, `
|
|
166
|
+
| Tracked hook events | Upstream canonical (codex-rs `HookEventName` enum): `PreToolUse`, `PostToolUse`, `PermissionRequest`, `PreCompact`, `PostCompact`, `SessionStart`, `UserPromptSubmit`, `SubagentStart`, `SubagentStop`, `Stop` (10 events). We currently wire a subset: `SessionStart`, `PreToolUse`, `PermissionRequest`, `UserPromptSubmit`, `Stop`. |
|
|
167
167
|
| Tracked handler types | `command` (emitted by default); `prompt` and `agent` available upstream but authored by hand |
|
|
168
168
|
| Other capabilities | `AGENTS.md`, `config.toml`, `mcp_servers`, sandbox policies, `.agents/skills/*/SKILL.md` (native Codex skill discovery path) |
|
|
169
169
|
| Version probe | `codex --version` |
|
package/llms-full.txt
CHANGED
|
@@ -6965,9 +6965,9 @@ title: "AI Toolkit - Codex CLI Compatibility"
|
|
|
6965
6965
|
category: reference
|
|
6966
6966
|
service: ai-toolkit
|
|
6967
6967
|
tags: [codex, compatibility, install, skills, hooks]
|
|
6968
|
-
version: "1.0.
|
|
6968
|
+
version: "1.0.3"
|
|
6969
6969
|
created: "2026-04-12"
|
|
6970
|
-
last_updated: "2026-05-
|
|
6970
|
+
last_updated: "2026-05-25"
|
|
6971
6971
|
description: "Reference for how ai-toolkit maps Claude-oriented skills, hooks, and plugin packs to Codex CLI."
|
|
6972
6972
|
---
|
|
6973
6973
|
|
|
@@ -7072,12 +7072,27 @@ This means Claude-only events such as `TaskCompleted`, `TeammateIdle`,
|
|
|
7072
7072
|
`~/.codex/hooks.json` (global layer). Non-Codex events are silently skipped.
|
|
7073
7073
|
`remove-hook` cleans both Claude and Codex targets.
|
|
7074
7074
|
|
|
7075
|
-
Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. The
|
|
7076
|
-
`UserPromptSubmit` governance hook
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7075
|
+
Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. The generated
|
|
7076
|
+
`UserPromptSubmit` governance hook does not set `AI_TOOLKIT_HOOK_FORMAT=json`
|
|
7077
|
+
by default because Codex currently renders `additionalContext` as visible hook
|
|
7078
|
+
context in the TUI. This keeps prompt-submit output quiet while preserving hook
|
|
7079
|
+
side effects and blocking decisions such as search-first Stop enforcement.
|
|
7080
|
+
|
|
7081
|
+
Codex `UserPromptSubmit` JSON output is event-specific. When emitting context,
|
|
7082
|
+
the hook must include the event name alongside the context:
|
|
7083
|
+
|
|
7084
|
+
```json
|
|
7085
|
+
{
|
|
7086
|
+
"hookSpecificOutput": {
|
|
7087
|
+
"hookEventName": "UserPromptSubmit",
|
|
7088
|
+
"additionalContext": "..."
|
|
7089
|
+
},
|
|
7090
|
+
"suppressOutput": true
|
|
7091
|
+
}
|
|
7092
|
+
```
|
|
7093
|
+
|
|
7094
|
+
Older `{"hookSpecificOutput":{"additionalContext":"..."}}` output can be valid
|
|
7095
|
+
JSON but fail newer Codex event-output validation.
|
|
7081
7096
|
|
|
7082
7097
|
Plain-text informational hook context is also silent by default in the shared
|
|
7083
7098
|
hook helper. Set `AI_TOOLKIT_HOOK_VERBOSE=1` only when debugging hook output
|
|
@@ -8880,7 +8895,7 @@ title: "Hooks Catalog"
|
|
|
8880
8895
|
category: reference
|
|
8881
8896
|
service: ai-toolkit
|
|
8882
8897
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
8883
|
-
version: "1.5.
|
|
8898
|
+
version: "1.5.6"
|
|
8884
8899
|
created: "2026-03-27"
|
|
8885
8900
|
last_updated: "2026-05-25"
|
|
8886
8901
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
@@ -8890,7 +8905,7 @@ description: "Complete reference of all ai-toolkit hooks: events, scripts, insta
|
|
|
8890
8905
|
|
|
8891
8906
|
## Overview
|
|
8892
8907
|
|
|
8893
|
-
ai-toolkit provides
|
|
8908
|
+
ai-toolkit provides 29 global hook entries across 14 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/`.
|
|
8894
8909
|
|
|
8895
8910
|
## Supported Surface
|
|
8896
8911
|
|
|
@@ -8962,6 +8977,10 @@ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
|
|
|
8962
8977
|
- `git push --force`
|
|
8963
8978
|
- `chmod -R 777`
|
|
8964
8979
|
|
|
8980
|
+
**Exemptions (avoid false positives):**
|
|
8981
|
+
- `git push --force-with-lease` / `--force-if-includes` — the safe force-push variants are allowed.
|
|
8982
|
+
- A single, non-chained `echo`/`printf`/`git commit`/`git tag` carrying a destructive token as *data* (e.g. a commit message mentioning `DROP TABLE`) is allowed. Chained commands (`&&`, `;`, `|`) are still inspected in full.
|
|
8983
|
+
|
|
8965
8984
|
### PreToolUse (file ops) — `guard-path.sh`
|
|
8966
8985
|
|
|
8967
8986
|
| Field | Value |
|
|
@@ -8991,12 +9010,29 @@ work, evidence-first debugging, KB-first research, and validation expectations.
|
|
|
8991
9010
|
Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
|
|
8992
9011
|
registers this command with `AI_TOOLKIT_HOOK_QUIET=1 AI_TOOLKIT_HOOK_FORMAT=json`.
|
|
8993
9012
|
This keeps the hook visually quiet (`suppressOutput: true`) while still
|
|
8994
|
-
injecting
|
|
9013
|
+
injecting event-specific JSON context before Claude starts working in runtimes
|
|
9014
|
+
that consume hidden context:
|
|
9015
|
+
|
|
9016
|
+
```json
|
|
9017
|
+
{
|
|
9018
|
+
"hookSpecificOutput": {
|
|
9019
|
+
"hookEventName": "UserPromptSubmit",
|
|
9020
|
+
"additionalContext": "..."
|
|
9021
|
+
},
|
|
9022
|
+
"suppressOutput": true
|
|
9023
|
+
}
|
|
9024
|
+
```
|
|
9025
|
+
|
|
8995
9026
|
That context is the proactive half of search-first enforcement; the paired
|
|
8996
9027
|
`stop-search-check.sh` remains the corrective half. In plain-text mode,
|
|
8997
9028
|
informational reminders are silent by default and require
|
|
8998
9029
|
`AI_TOOLKIT_HOOK_VERBOSE=1`.
|
|
8999
9030
|
|
|
9031
|
+
Codex-generated hooks intentionally run this script without
|
|
9032
|
+
`AI_TOOLKIT_HOOK_FORMAT=json` by default because Codex renders
|
|
9033
|
+
`additionalContext` visibly in the TUI; the search-first flag side effect still
|
|
9034
|
+
arms the corrective Stop hook.
|
|
9035
|
+
|
|
9000
9036
|
### UserPromptSubmit (usage tracking) — `track-usage.sh`
|
|
9001
9037
|
|
|
9002
9038
|
| Field | Value |
|
|
@@ -9006,7 +9042,7 @@ informational reminders are silent by default and require
|
|
|
9006
9042
|
| Script | `~/.softspark/ai-toolkit/hooks/track-usage.sh` |
|
|
9007
9043
|
| Fires | Before Claude starts working on a submitted prompt |
|
|
9008
9044
|
|
|
9009
|
-
**Action:** Records skill invocations (slash commands like `/commit`, `/review`) to `~/.softspark/ai-toolkit/stats.json` for local usage analytics. Non-slash prompts are ignored.
|
|
9045
|
+
**Action:** Records skill invocations (slash commands like `/commit`, `/review`) to `~/.softspark/ai-toolkit/stats.json` for local usage analytics. Non-slash prompts are ignored. Stats writes are best-effort and stay silent if the local state path is not writable.
|
|
9010
9046
|
|
|
9011
9047
|
### PostToolUse (edit feedback) — `post-tool-use.sh`
|
|
9012
9048
|
|
|
@@ -9263,6 +9299,19 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
|
|
|
9263
9299
|
|
|
9264
9300
|
**Overrides:** `CLAUDE_SKIP_COHESION=1` (one-off), `CLAUDE_HOOK_BOOTSTRAP=1` (when editing the hook itself). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
9265
9301
|
|
|
9302
|
+
### PostToolUse (loop guard) — `loop-guard.sh`
|
|
9303
|
+
|
|
9304
|
+
| Field | Value |
|
|
9305
|
+
|-------|-------|
|
|
9306
|
+
| Event | `PostToolUse` |
|
|
9307
|
+
| Matcher | `Bash\|Edit\|MultiEdit\|Write` |
|
|
9308
|
+
| Script | `~/.softspark/ai-toolkit/hooks/loop-guard.sh` |
|
|
9309
|
+
| Fires | After every Bash command or file edit |
|
|
9310
|
+
|
|
9311
|
+
**Action:** Advisory only, never blocks. Hashes a `tool|identity` signature of each action (command for Bash; file path + new content for edits) and keeps the last `AI_TOOLKIT_LOOP_WINDOW` (default 6) hashes per session. When the same signature repeats `AI_TOOLKIT_LOOP_THRESHOLD` times (default 3) it emits a `PostToolUse` `additionalContext` advisory telling Claude to reassess instead of retrying. Catches successful-but-identical loops that the `/repeat` circuit breaker (which only counts failures) does not. Edits track content, so normal iterative editing of one file does not trip it. Only short hashes are stored — never raw payloads.
|
|
9312
|
+
|
|
9313
|
+
**Tunables:** `AI_TOOLKIT_LOOP_WINDOW`, `AI_TOOLKIT_LOOP_THRESHOLD`. Skipped when `TOOLKIT_HOOK_PROFILE=minimal`; honours `AI_TOOLKIT_DISABLED_HOOKS`.
|
|
9314
|
+
|
|
9266
9315
|
### PostToolUse (search-first tracker) — `search-tracker.sh`
|
|
9267
9316
|
|
|
9268
9317
|
| Field | Value |
|
|
@@ -9340,6 +9389,8 @@ Set in `.claude/settings.local.json`:
|
|
|
9340
9389
|
| `standard` | All hooks (default) |
|
|
9341
9390
|
| `strict` | Standard + mypy --strict on task completion |
|
|
9342
9391
|
|
|
9392
|
+
**Disabling individual hooks:** set `AI_TOOLKIT_DISABLED_HOOKS` to a comma-separated list of hook names (with or without `.sh`), e.g. `{ "env": { "AI_TOOLKIT_DISABLED_HOOKS": "loop-guard,quality-check" } }`. Listed hooks become no-ops. This covers profile-gated hooks only; the safety guards (`guard-destructive`/`guard-path`/`guard-config`) intentionally cannot be env-disabled — remove them deliberately with `ai-toolkit remove-hook`.
|
|
9393
|
+
|
|
9343
9394
|
Non-blocking informational context is silent in plain-text mode by default while
|
|
9344
9395
|
side effects and blocking decisions still run. Set `AI_TOOLKIT_HOOK_VERBOSE=1`
|
|
9345
9396
|
only when debugging hook context locally. `AI_TOOLKIT_HOOK_QUIET=1` keeps hook
|
|
@@ -9421,7 +9472,7 @@ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
|
|
|
9421
9472
|
|
|
9422
9473
|
**Hook script not found:**
|
|
9423
9474
|
```bash
|
|
9424
|
-
ls ~/.softspark/ai-toolkit/hooks/ # should list
|
|
9475
|
+
ls ~/.softspark/ai-toolkit/hooks/ # should list 28 .sh files (plus _profile-check.sh + _locate-toolkit.sh + _hook-io.sh + _search-capability.sh helpers + test-cohesion-map.json)
|
|
9425
9476
|
ai-toolkit update # re-copies scripts
|
|
9426
9477
|
```
|
|
9427
9478
|
|
|
@@ -9988,7 +10039,7 @@ service: ai-toolkit
|
|
|
9988
10039
|
tags: [mcp, editors, compatibility, codex, cursor]
|
|
9989
10040
|
version: "1.1.0"
|
|
9990
10041
|
created: "2026-04-12"
|
|
9991
|
-
last_updated: "2026-
|
|
10042
|
+
last_updated: "2026-05-30"
|
|
9992
10043
|
description: "Official MCP support matrix and native config targets for editors supported by ai-toolkit."
|
|
9993
10044
|
---
|
|
9994
10045
|
|
|
@@ -11716,7 +11767,7 @@ service: ai-toolkit
|
|
|
11716
11767
|
tags: [editors, platforms, generators, integration, ecosystem]
|
|
11717
11768
|
version: "1.3.0"
|
|
11718
11769
|
created: "2026-04-23"
|
|
11719
|
-
last_updated: "2026-05-
|
|
11770
|
+
last_updated: "2026-05-30"
|
|
11720
11771
|
description: "Human-readable view of scripts/ecosystem_tools.json — the canonical list of tools ai-toolkit integrates with (Claude Code + 11 editors), their documentation URLs, config paths, our generators, and tracked capability markers."
|
|
11721
11772
|
---
|
|
11722
11773
|
|
|
@@ -11741,7 +11792,7 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
11741
11792
|
| Release notes | https://github.com/anthropics/claude-code/releases |
|
|
11742
11793
|
| Config paths | `~/.claude/settings.json`, `.claude/settings.local.json`, `CLAUDE.md`, `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `~/.claude/themes/*.json` (v2.1.118+) |
|
|
11743
11794
|
| Our generators | — (Claude Code is the primary target; toolkit content ships directly as `.md` files and `settings.json` merges) |
|
|
11744
|
-
| Tracked hook events | Core: `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Notification`. Tool: `PreToolUse`, `PostToolUse`. Turn: `Stop`, `StopFailure`. Subagent: `SubagentStart`, `SubagentStop`. Compaction: `PreCompact`, `PostCompact`. Permissions: `PermissionRequest`, `PermissionDenied`. Elicitation: `Elicitation`, `ElicitationResult`. Teams: `TaskCreated`, `TaskCompleted`, `TeammateIdle`. Worktrees/env: `WorktreeCreate`, `WorktreeRemove`, `CwdChanged`, `FileChanged`, `ConfigChange`. Setup: `Setup`, `InstructionsLoaded` |
|
|
11795
|
+
| Tracked hook events | Core: `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Notification`, `MessageDisplay`. Tool: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PostToolBatch`. Turn: `Stop`, `StopFailure`, `UserPromptExpansion`. Subagent: `SubagentStart`, `SubagentStop`. Compaction: `PreCompact`, `PostCompact`. Permissions: `PermissionRequest`, `PermissionDenied`. Elicitation: `Elicitation`, `ElicitationResult`. Teams: `TaskCreated`, `TaskCompleted`, `TeammateIdle`. Worktrees/env: `WorktreeCreate`, `WorktreeRemove`, `CwdChanged`, `FileChanged`, `ConfigChange`. Setup: `Setup`, `InstructionsLoaded` |
|
|
11745
11796
|
| Tracked handler types | `command`, `prompt`, `agent`, `mcp_tool` |
|
|
11746
11797
|
| Other capabilities | slash commands, MCP server/client, sub-agent, output style, `SKILL.md` (≥500 lines warn) |
|
|
11747
11798
|
| Version probe | `claude --version` |
|
|
@@ -11874,7 +11925,7 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
11874
11925
|
| Release notes | https://github.com/openai/codex/releases |
|
|
11875
11926
|
| Config paths | `AGENTS.md`, `.agents/rules/*.md`, `.agents/skills/*/SKILL.md`, `.codex/hooks.json`, `~/.codex/config.toml` |
|
|
11876
11927
|
| Our generators | `scripts/generate_codex.py`, `scripts/generate_codex_rules.py`, `scripts/generate_codex_hooks.py`, `scripts/generate_codex_skills.py` (opt-in via `--codex-skills`) |
|
|
11877
|
-
| Tracked hook events | `PreToolUse`, `PostToolUse`, `SessionStart`, `UserPromptSubmit`, `
|
|
11928
|
+
| Tracked hook events | Upstream canonical (codex-rs `HookEventName` enum): `PreToolUse`, `PostToolUse`, `PermissionRequest`, `PreCompact`, `PostCompact`, `SessionStart`, `UserPromptSubmit`, `SubagentStart`, `SubagentStop`, `Stop` (10 events). We currently wire a subset: `SessionStart`, `PreToolUse`, `PermissionRequest`, `UserPromptSubmit`, `Stop`. |
|
|
11878
11929
|
| Tracked handler types | `command` (emitted by default); `prompt` and `agent` available upstream but authored by hand |
|
|
11879
11930
|
| Other capabilities | `AGENTS.md`, `config.toml`, `mcp_servers`, sandbox policies, `.agents/skills/*/SKILL.md` (native Codex skill discovery path) |
|
|
11880
11931
|
| Version probe | `codex --version` |
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
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",
|
package/scripts/audit_skills.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"""Skill & Agent Security Auditor.
|
|
3
3
|
|
|
4
4
|
Deterministic scanner for ai-toolkit skills and agents.
|
|
5
|
-
Detects dangerous code patterns, hardcoded secrets,
|
|
5
|
+
Detects dangerous code patterns, hardcoded secrets, permission issues, and
|
|
6
|
+
invisible/smuggled Unicode in shipped prompt text.
|
|
6
7
|
|
|
7
8
|
Stdlib-only. JSON output to stdout. Non-zero exit on HIGH findings.
|
|
8
9
|
|
|
@@ -22,6 +23,7 @@ from __future__ import annotations
|
|
|
22
23
|
import json
|
|
23
24
|
import re
|
|
24
25
|
import sys
|
|
26
|
+
import unicodedata
|
|
25
27
|
from pathlib import Path
|
|
26
28
|
|
|
27
29
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
@@ -149,6 +151,73 @@ def scan_secrets(filepath: Path, findings: list[Finding]) -> None:
|
|
|
149
151
|
findings.append(Finding(severity, rel, lineno, regex, desc))
|
|
150
152
|
|
|
151
153
|
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
# Unicode safety — invisible / smuggled characters in shipped prompt text.
|
|
156
|
+
# Prompt files (skills, agents, rules, personas, mcp-templates) ARE the
|
|
157
|
+
# product. A poisoned PR can carry instructions a human reviewer cannot see:
|
|
158
|
+
# regex-over-decoded-text checks (above) never catch them.
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
# ASCII smuggling: U+E0000–U+E007F mirror ASCII inside Unicode "tag" chars.
|
|
162
|
+
_UNICODE_TAG_BLOCK = range(0xE0000, 0xE0080)
|
|
163
|
+
|
|
164
|
+
# Trojan Source bidi controls (CVE-2021-42574) — reorder rendered text vs. its
|
|
165
|
+
# logical/source order, hiding instructions from a reviewer.
|
|
166
|
+
_UNICODE_BIDI_HIGH = frozenset({
|
|
167
|
+
0x202A, 0x202B, 0x202C, 0x202D, 0x202E, # LRE RLE PDF LRO RLO
|
|
168
|
+
0x2066, 0x2067, 0x2068, 0x2069, # LRI RLI FSI PDI
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
# Invisible / zero-width formatting that can hide or splice text.
|
|
172
|
+
# U+200D (ZERO WIDTH JOINER) is deliberately EXCLUDED — it is required by
|
|
173
|
+
# legitimate emoji sequences and i18n text, so flagging it floods false
|
|
174
|
+
# positives and trains maintainers to disable the gate.
|
|
175
|
+
_UNICODE_INVISIBLE_WARN = frozenset({
|
|
176
|
+
0x200B, 0x200C, 0x200E, 0x200F, 0x2060, 0xFEFF, 0x00AD,
|
|
177
|
+
0x180E, 0x115F, 0x1160, 0x3164, 0xFFA0, 0x17B4, 0x17B5,
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _char_name(cp: int) -> str:
|
|
182
|
+
"""Best-effort Unicode name for diagnostics."""
|
|
183
|
+
try:
|
|
184
|
+
return unicodedata.name(chr(cp))
|
|
185
|
+
except ValueError:
|
|
186
|
+
return f"U+{cp:04X}"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def scan_unicode(filepath: Path, findings: list[Finding]) -> None:
|
|
190
|
+
"""Flag invisible / smuggled Unicode in shipped prompt text."""
|
|
191
|
+
try:
|
|
192
|
+
text = filepath.read_text(encoding="utf-8", errors="replace")
|
|
193
|
+
except OSError:
|
|
194
|
+
return
|
|
195
|
+
rel = str(filepath)
|
|
196
|
+
for lineno, line in enumerate(text.splitlines(), 1):
|
|
197
|
+
for ch in line:
|
|
198
|
+
cp = ord(ch)
|
|
199
|
+
if cp < 0x80: # plain ASCII — fast path, always safe
|
|
200
|
+
continue
|
|
201
|
+
if cp in _UNICODE_TAG_BLOCK:
|
|
202
|
+
findings.append(Finding(
|
|
203
|
+
"HIGH", rel, lineno, "unicode-tag-block",
|
|
204
|
+
f"Unicode tag char {_char_name(cp)} (U+{cp:04X}) — "
|
|
205
|
+
"ASCII smuggling / invisible prompt injection",
|
|
206
|
+
))
|
|
207
|
+
elif cp in _UNICODE_BIDI_HIGH:
|
|
208
|
+
findings.append(Finding(
|
|
209
|
+
"HIGH", rel, lineno, "unicode-bidi-control",
|
|
210
|
+
f"Bidi control {_char_name(cp)} (U+{cp:04X}) — "
|
|
211
|
+
"Trojan Source text reordering",
|
|
212
|
+
))
|
|
213
|
+
elif cp in _UNICODE_INVISIBLE_WARN:
|
|
214
|
+
findings.append(Finding(
|
|
215
|
+
"WARN", rel, lineno, "unicode-invisible",
|
|
216
|
+
f"Invisible/zero-width char {_char_name(cp)} (U+{cp:04X}) — "
|
|
217
|
+
"verify it is intentional",
|
|
218
|
+
))
|
|
219
|
+
|
|
220
|
+
|
|
152
221
|
# Description quality — per Anthropic docs (code.claude.com/docs/en/skills.md):
|
|
153
222
|
# description + when_to_use combined ≤ 1536 chars; first sentence carries
|
|
154
223
|
# the trigger keywords that let the LLM route to this skill.
|
|
@@ -373,15 +442,26 @@ def audit(toolkit_root: Path) -> list[Finding]:
|
|
|
373
442
|
scan_file_patterns(sh, BASH_WARN, "WARN", findings)
|
|
374
443
|
scan_secrets(sh, findings)
|
|
375
444
|
|
|
376
|
-
# Secrets in any text file
|
|
445
|
+
# Secrets + invisible Unicode in any text file
|
|
377
446
|
for md in skill_dir.rglob("*.md"):
|
|
378
447
|
scan_secrets(md, findings)
|
|
448
|
+
scan_unicode(md, findings)
|
|
379
449
|
|
|
380
450
|
# Scan agents
|
|
381
451
|
if agents.is_dir():
|
|
382
452
|
for agent_md in sorted(agents.glob("*.md")):
|
|
383
453
|
check_agent(agent_md, findings)
|
|
384
454
|
scan_secrets(agent_md, findings)
|
|
455
|
+
scan_unicode(agent_md, findings)
|
|
456
|
+
|
|
457
|
+
# Unicode safety across the rest of the shipped prompt surface.
|
|
458
|
+
for extra in ("rules", "personas", "mcp-templates"):
|
|
459
|
+
extra_dir = app / extra
|
|
460
|
+
if not extra_dir.is_dir():
|
|
461
|
+
continue
|
|
462
|
+
for f in sorted(extra_dir.rglob("*")):
|
|
463
|
+
if f.is_file() and f.suffix in (".md", ".json"):
|
|
464
|
+
scan_unicode(f, findings)
|
|
385
465
|
|
|
386
466
|
# Sort: HIGH first, then WARN, then INFO
|
|
387
467
|
order = {"HIGH": 0, "WARN": 1, "INFO": 2}
|