@softspark/ai-toolkit 4.3.1 → 4.3.2

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 CHANGED
@@ -7,6 +7,40 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v4.3.2 - quiet hooks and no-RAG search-first hardening (2026-05-21)
11
+
12
+ Patch release. Fixes noisy lifecycle hook output in Codex and Claude prompt-submit flows while preserving search-first enforcement and blocking decisions.
13
+
14
+ ### Fixed
15
+
16
+ - **Quiet Codex startup hooks** - `scripts/generate_codex_hooks.py` now prefixes generated Codex hook commands with `AI_TOOLKIT_HOOK_QUIET=1`, preventing informational `SessionStart` and prompt reminders from appearing as visible hook context.
17
+ - **Quiet Claude prompt-submit hook** - `app/hooks.json` now installs `user-prompt-submit.sh` with `AI_TOOLKIT_HOOK_QUIET=1`, suppressing non-blocking prompt governance output while still arming the per-session search-first flag.
18
+ - **No-RAG false positives** - `_search-capability.sh` now detects search providers from actual MCP server definitions only, so hook matchers and permission allowlists no longer make no-RAG installs block incorrectly.
19
+ - **Codex search tracking gap** - `stop-search-check.sh` now checks the Codex TUI log for search tool calls after the search-first flag timestamp before blocking, covering Codex MCP calls that do not fire the shared `PostToolUse` tracker.
20
+
21
+ ### Changed
22
+
23
+ - **Hook output helper** - `_hook-io.sh` supports `AI_TOOLKIT_HOOK_QUIET=1` for non-blocking context output.
24
+ - **Runtime hook docs** - `kb/reference/hooks-catalog.md` and `kb/reference/codex-cli-compatibility.md` document quiet mode and the Codex search-first fallback.
25
+ - **Manifest hook count** - `manifest.json` now describes the current 28 hook entries across 14 lifecycle events.
26
+
27
+ ### Tests
28
+
29
+ - **Hook quiet-mode coverage** - `tests/test_hooks.bats`, `tests/test_codex.bats`, and `tests/test_install.bats` cover quiet mode for `SessionStart`, `UserPromptSubmit`, `PostToolUse`, Codex hook generation, and installed Claude hook configuration.
30
+ - **Search-first flow coverage** - `tests/test_search_first_flow.bats` covers real-provider detection, no-RAG behavior, custom `customer-rag` style providers, and Codex log fallback.
31
+
32
+ ### Ecosystem
33
+
34
+ - **Snapshot refresh** - `benchmarks/ecosystem-doctor-snapshot.json` refreshed after class A/C upstream documentation and version drift review. No generator contract changes were required.
35
+
36
+ ### Verification
37
+
38
+ - `npm test` - 1142 passing.
39
+ - `python3 scripts/validate.py --strict` - passed.
40
+ - `python3 scripts/audit_skills.py --ci` - passed with 0 HIGH / 0 WARN.
41
+
42
+ ---
43
+
10
44
  ## v4.3.1 - per-session search-first flag (2026-05-19)
11
45
 
12
46
  Patch release. Fixes a cross-session race condition in the search-first enforcement trio (`user-prompt-submit.sh` + `search-tracker.sh` + `stop-search-check.sh`): the single global flag file `~/.softspark/ai-toolkit/state/search-required.flag` was shared by every parallel Claude Code window, so a Stop in session B could consume session A's flag (or vice versa), blocking unrelated turns with someone else's prompt. Also unblocks `bats 1.13` regression in the test-cohesion runner default.
package/README.md CHANGED
@@ -6,16 +6,17 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
  [![Skills](https://img.shields.io/badge/skills-107-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
- [![Tests](https://img.shields.io/badge/tests-1133%20passing-success)](tests/)
9
+ [![Tests](https://img.shields.io/badge/tests-1142%20passing-success)](tests/)
10
10
 
11
- ## What's New in v4.3.1
11
+ ## What's New in v4.3.2
12
12
 
13
- Patch release. Fixes a cross-session race in the search-first enforcement trio: the single global `search-required.flag` was shared by every parallel Claude Code window, so a Stop in one session could block another with someone else's prompt. Also unblocks the `bats 1.13` regression in the test-cohesion runner.
13
+ Patch release. Fixes noisy hook output and hardens search-first behavior across Claude and Codex.
14
14
 
15
- - **Per-session search-first flag**: `user-prompt-submit.sh`, `search-tracker.sh`, and `stop-search-check.sh` now key the flag by `session_id` (`search-required-<session_id>.flag`), so parallel Claude Code windows no longer interfere with each other.
16
- - **Stale-flag GC**: `session-start.sh` deletes per-session flags older than 60 minutes, so crashed sessions leave no residue.
17
- - **`bats 1.13` compatibility**: `scripts/test_cohesion.py` no longer passes `--no-parallelize-within-files` (it now requires `--jobs 2` in bats 1.13 and was redundant in sequential mode anyway).
18
- - **Two new isolation tests**: `tests/test_search_first_flow.bats` verifies per-session flag scoping for both Stop and PostToolUse paths.
15
+ - **Quiet hook context**: Codex startup hooks and Claude/Codex `UserPromptSubmit` now suppress non-blocking reminder output while preserving side effects and blocking decisions.
16
+ - **Search provider detection**: search-first hooks now count only real MCP server definitions, not hook matchers or permission allowlists, so no-RAG installs stay advisory instead of blocked.
17
+ - **Codex search-first fallback**: `stop-search-check.sh` recognizes search calls recorded in the Codex TUI log when MCP tool calls do not trigger `PostToolUse`.
18
+ - **Runtime refresh coverage**: installer tests now assert that Claude `UserPromptSubmit` is installed with quiet mode enabled.
19
+ - **Ecosystem snapshot refresh**: release prep refreshed upstream editor/tool drift baselines after class A/C documentation and version drift review.
19
20
 
20
21
  See [CHANGELOG.md](CHANGELOG.md) for full history.
21
22
 
@@ -125,7 +126,7 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
125
126
  | `skills/` (hybrid) | 30 | Slash commands with agent knowledge base |
126
127
  | `skills/` (knowledge) | 45 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
127
128
  | `agents/` | 44 | Specialized agents across 10 categories |
128
- | `hooks/` | 22 global + 5 skill-scoped | Quality gates, path safety, prompt governance, session lifecycle |
129
+ | `hooks/` | 28 entries / 14 events | Quality gates, path safety, prompt governance, session lifecycle |
129
130
  | `plugins/` | 11 packs | Opt-in domain bundles (security, research, frontend, enterprise, 6 language packs) |
130
131
  | `constitution.md` | 6 articles | Machine-enforced safety rules |
131
132
  | `rules/` | auto-injected | Language-specific and custom rules injected into your configs |
@@ -148,7 +149,7 @@ ai-toolkit/
148
149
  │ └── ARCHITECTURE.md # Full system design
149
150
  ├── kb/ # Reference docs, procedures, plans
150
151
  ├── scripts/ # Validation, install, evaluation scripts
151
- ├── tests/ # Bats test suite (1133 tests)
152
+ ├── tests/ # Bats test suite (1142 tests)
152
153
  └── CHANGELOG.md
153
154
  ```
154
155
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-toolkit",
3
3
  "description": "Professional-grade Claude Code toolkit with persona presets, skill security auditor, expanded lifecycle hooks, experimental opt-in plugin packs, benchmark harvesting, and multi-tool support.",
4
- "version": "4.3.1",
4
+ "version": "4.3.2",
5
5
  "author": {
6
6
  "name": "SoftSpark",
7
7
  "url": "https://github.com/softspark"
@@ -8,7 +8,7 @@ Universal multi-agent system for software development. Works across all reposito
8
8
  |-----------|-------|
9
9
  | Agents | See agents catalog |
10
10
  | Skills | See skills catalog |
11
- | Hooks | 12 events / 22 entries (SessionStart ×3, Notification ×1, PreToolUse ×4, UserPromptSubmit ×2, PostToolUse ×2, Stop ×3, TaskCompleted ×1, TeammateIdle ×1, SubagentStart ×1, SubagentStop ×1, PreCompact ×2, SessionEnd ×1) |
11
+ | Hooks | 14 events / 28 entries (SessionStart ×3, Notification ×1, PreToolUse ×5, UserPromptSubmit ×2, PostToolUse ×4, Stop ×4, TaskCompleted ×1, TeammateIdle ×1, SubagentStart ×1, SubagentStop ×1, PreCompact ×2, SessionEnd ×1, InstructionsLoaded ×1, ConfigChange ×1) |
12
12
 
13
13
  ---
14
14
 
@@ -332,7 +332,9 @@ Lead Session (You)
332
332
  | `UserPromptSubmit` | Before prompt execution | Prompt governance reminder |
333
333
  | `UserPromptSubmit` | Before prompt execution | Usage tracking (skill invocations) |
334
334
  | `PostToolUse` | After edit/write tools | Lightweight validation reminder |
335
+ | `PostToolUse` | After search tools | Clears the per-session search-first flag |
335
336
  | `Stop` | After Claude response | Multi-language quality check + saves session context |
337
+ | `Stop` | After Claude response | Blocks skipped search-first only when a real MCP/Web search provider is configured, with Codex log fallback |
336
338
  | `TaskCompleted` | Teammate marks task done | Multi-language lint + type check (blocking) |
337
339
  | `TeammateIdle` | Teammate goes idle | Reminds to verify completeness |
338
340
  | `SubagentStart` | Subagent starts | Scope reminder for spawned subagents |
@@ -353,6 +355,9 @@ Lead Session (You)
353
355
 
354
356
  Language rules are propagated to **all configured editors** — not just Claude. `dir_rules_shared.build_language_rules()` reads `app/rules/<lang>/*.md`, strips frontmatter, and returns combined content per language. Each directory-based generator (Cursor, Windsurf, Cline, Roo, Augment, Antigravity, Codex) emits `ai-toolkit-lang-<lang>` files in its native format. Registered custom rules (`~/.softspark/ai-toolkit/rules/`) are similarly propagated as `ai-toolkit-custom-<name>` files via `build_registered_rules()`.
355
357
 
358
+ ### Codex Integration
359
+ Codex receives `AGENTS.md`, `.agents/rules/*.md`, optional `.agents/skills/*`, and `.codex/hooks.json`. `generate_codex_hooks.py` emits only Codex-supported lifecycle events and prefixes commands with `AI_TOOLKIT_HOOK_QUIET=1`, so informational hook context is not shown at session start or prompt submit while side effects and blocking Stop decisions still run. Claude's bundled `UserPromptSubmit` hook also runs in quiet mode for the same reason.
360
+
356
361
  ### opencode Integration (v2.5.0+)
357
362
  opencode is the 11th supported editor. Five generators handle its integration surface:
358
363
 
@@ -58,6 +58,9 @@ hook_new_content() {
58
58
 
59
59
  hook_emit_context() {
60
60
  local message="$1"
61
+ if [ "${AI_TOOLKIT_HOOK_QUIET:-0}" = "1" ]; then
62
+ return 0
63
+ fi
61
64
  if [ "${AI_TOOLKIT_HOOK_FORMAT:-}" = "json" ]; then
62
65
  jq -nc --arg msg "$message" \
63
66
  '{"hookSpecificOutput":{"additionalContext":$msg},"suppressOutput":true}'
@@ -24,23 +24,71 @@ ai_toolkit_has_search_provider() {
24
24
  [ -n "${AI_TOOLKIT_SEARCH_PROVIDER:-}" ] && return 0
25
25
  [ -n "${CLAUDE_SEARCH_PROVIDER:-}" ] && return 0
26
26
 
27
- local candidates=(
27
+ local json_candidates=(
28
28
  "$PWD/.mcp.json"
29
+ "$PWD/.claude/settings.local.json"
30
+ "$PWD/.claude/settings.json"
29
31
  "$PWD/.claude/mcp.json"
30
32
  "$PWD/.cursor/mcp.json"
31
33
  "$PWD/.gemini/settings.json"
34
+ "$HOME/.mcp.json"
32
35
  "$HOME/.claude.json"
33
36
  "$HOME/.claude/settings.json"
34
- "$HOME/.codex/config.toml"
37
+ "$HOME/.cursor/mcp.json"
35
38
  "$HOME/.gemini/settings.json"
36
39
  )
37
40
  local path
38
- for path in "${candidates[@]}"; do
41
+ for path in "${json_candidates[@]}"; do
42
+ [ -f "$path" ] || continue
43
+ if ai_toolkit_json_has_search_provider "$path"; then
44
+ return 0
45
+ fi
46
+ done
47
+
48
+ local toml_candidates=(
49
+ "$HOME/.codex/config.toml"
50
+ )
51
+ for path in "${toml_candidates[@]}"; do
39
52
  [ -f "$path" ] || continue
40
- if grep -Eqi 'rag[-_]?mcp|smart_query|hybrid_search_kb|crag_search|multi_hop_search|websearch|web-fetch|web_fetch|web_search' "$path"; then
53
+ if ai_toolkit_toml_has_search_provider "$path"; then
41
54
  return 0
42
55
  fi
43
56
  done
44
57
 
45
58
  return 1
46
59
  }
60
+
61
+ ai_toolkit_search_provider_pattern() {
62
+ printf '%s\n' '(^|[^[:alnum:]])(([^[:space:]]*[-_])?rag([-_][^[:space:]]*)?|rag[-_]?mcp|web[-_]?search|search)([^[:alnum:]]|$)'
63
+ }
64
+
65
+ ai_toolkit_json_has_search_provider() {
66
+ local path="$1"
67
+ local pattern
68
+ pattern="$(ai_toolkit_search_provider_pattern)"
69
+
70
+ command -v jq >/dev/null 2>&1 || return 1
71
+ jq -er '
72
+ [
73
+ (.mcpServers // {} | to_entries[]? | .key),
74
+ (.mcp_servers // {} | to_entries[]? | .key),
75
+ (.mcp // {} | to_entries[]? | .key)
76
+ ] | join(" ")
77
+ ' "$path" 2>/dev/null | grep -Eiq "$pattern"
78
+ }
79
+
80
+ ai_toolkit_toml_has_search_provider() {
81
+ local path="$1"
82
+ local pattern
83
+ pattern="$(ai_toolkit_search_provider_pattern)"
84
+
85
+ awk '
86
+ /^\[mcp_servers[."]/ {
87
+ line=$0
88
+ sub(/^\[mcp_servers[."]?/, "", line)
89
+ sub(/"\]$/, "", line)
90
+ sub(/\]$/, "", line)
91
+ print line
92
+ }
93
+ ' "$path" 2>/dev/null | grep -Eiq "$pattern"
94
+ }
@@ -45,7 +45,9 @@ for CONFIG in "${CONFIG_FILES[@]}"; do
45
45
  [ -z "$CMD" ] && continue
46
46
  if ! command -v "$CMD" >/dev/null 2>&1; then
47
47
  HINT=$(get_install_hint "$CMD")
48
- echo "MCP health: ${SERVER_NAME} command not found (${CMD}). Install with: ${HINT}"
48
+ if [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ]; then
49
+ echo "MCP health: ${SERVER_NAME} command not found (${CMD}). Install with: ${HINT}"
50
+ fi
49
51
  fi
50
52
  done <<< "$SERVERS"
51
53
  done
@@ -2,7 +2,7 @@
2
2
  # search-tracker.sh — Clear search-required flag when a search tool runs.
3
3
  #
4
4
  # Fires on: PostToolUse
5
- # Matcher: mcp__rag-mcp__smart_query|mcp__rag-mcp__hybrid_search_kb|mcp__rag-mcp__crag_search|mcp__rag-mcp__multi_hop_search|WebSearch|WebFetch
5
+ # Matcher: mcp__.*__(smart_query|hybrid_search_kb|crag_search|multi_hop_search|verify_answer)|WebSearch|WebFetch
6
6
  # Non-blocking: always exits 0.
7
7
  # Skipped when TOOLKIT_HOOK_PROFILE=minimal.
8
8
  #
@@ -4,13 +4,19 @@
4
4
  # Fires on: SessionStart (startup|compact)
5
5
  # Output goes to Claude's context as plain text.
6
6
 
7
- # 1. Mandatory rules reminder
8
- echo "MANDATORY: Before answering ANY technical question, apply ALL rules from your CLAUDE.md files (global + project). Follow the exact order of operations defined there. Do NOT skip mandatory steps even if you think you already know the answer."
9
- echo "REMINDER: When writing features or fixing bugs, ensure tests cover the changes. When modifying API, config, or setup, update relevant documentation. Propose these steps to the user — do not silently skip them."
10
-
11
7
  # shellcheck source=_locate-toolkit.sh
12
8
  source "$(dirname "$0")/_locate-toolkit.sh"
13
9
 
10
+ emit_context() {
11
+ if [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ]; then
12
+ printf '%s\n' "$1"
13
+ fi
14
+ }
15
+
16
+ # 1. Mandatory rules reminder
17
+ emit_context "MANDATORY: Before answering ANY technical question, apply ALL rules from your CLAUDE.md files (global + project). Follow the exact order of operations defined there. Do NOT skip mandatory steps even if you think you already know the answer."
18
+ emit_context "REMINDER: When writing features or fixing bugs, ensure tests cover the changes. When modifying API, config, or setup, update relevant documentation. Propose these steps to the user — do not silently skip them."
19
+
14
20
  # 1a. Reset per-session edit state (used by revert-guard, test-cohesion, quality-gate)
15
21
  SESSION_ID_INPUT=""
16
22
  if [ ! -t 0 ]; then
@@ -29,7 +35,7 @@ find "$HOME/.softspark/ai-toolkit/state" -maxdepth 1 -name 'search-required-*.fl
29
35
  # 2. Check for updates (cached, max once per 24h, non-blocking)
30
36
  VERSION_MSG=$(python3 "$TOOLKIT_DIR/scripts/version_check.py" 2>/dev/null)
31
37
  if [ -n "$VERSION_MSG" ]; then
32
- echo "$VERSION_MSG"
38
+ emit_context "$VERSION_MSG"
33
39
  # Strip shell/AppleScript/PowerShell metacharacters before interpolating into
34
40
  # notification commands. VERSION_MSG is version_check.py output which should
35
41
  # be plain ASCII, but sanitize anyway as defense in depth.
@@ -46,20 +52,20 @@ fi
46
52
 
47
53
  # 3. Load session context (if available)
48
54
  SESSION_FILE=".claude/session-context.md"
49
- if [ -f "$SESSION_FILE" ]; then
50
- echo "=== Session Context ==="
55
+ if [ -f "$SESSION_FILE" ] && [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ]; then
56
+ printf '%s\n' "=== Session Context ==="
51
57
  cat "$SESSION_FILE"
52
- echo "====================="
58
+ printf '%s\n' "====================="
53
59
  fi
54
60
 
55
61
  # 3. Load active instincts (if any)
56
62
  INSTINCTS_DIR=".claude/instincts"
57
- if [ -d "$INSTINCTS_DIR" ] && ls "$INSTINCTS_DIR"/*.md >/dev/null 2>&1; then
58
- echo "=== Active Instincts ==="
63
+ if [ -d "$INSTINCTS_DIR" ] && [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ] && ls "$INSTINCTS_DIR"/*.md >/dev/null 2>&1; then
64
+ printf '%s\n' "=== Active Instincts ==="
59
65
  for f in "$INSTINCTS_DIR"/*.md; do
60
- echo "- $(head -1 "$f")"
66
+ printf '%s\n' "- $(head -1 "$f")"
61
67
  done
62
- echo "========================"
68
+ printf '%s\n' "========================"
63
69
  fi
64
70
 
65
71
  exit 0
@@ -31,6 +31,59 @@ if ! ai_toolkit_has_search_provider; then
31
31
  exit 0
32
32
  fi
33
33
 
34
+ ai_toolkit_codex_log_has_search_since() {
35
+ local flag="$1"
36
+ local log="$HOME/.codex/log/codex-tui.log"
37
+ [ -f "$log" ] || return 1
38
+
39
+ python3 - "$flag" "$log" <<'PY' 2>/dev/null
40
+ import re
41
+ import sys
42
+ from datetime import datetime
43
+ from pathlib import Path
44
+
45
+ flag_path = Path(sys.argv[1])
46
+ log_path = Path(sys.argv[2])
47
+ try:
48
+ since = int(flag_path.read_text(encoding="utf-8").splitlines()[0])
49
+ except (OSError, ValueError, IndexError):
50
+ sys.exit(1)
51
+
52
+ tool_pattern = re.compile(
53
+ r"(ToolCall: (mcp__[^ ]*__(smart_query|hybrid_search_kb|crag_search|multi_hop_search|verify_answer)|web_(search|fetch))|"
54
+ r'tool\.name="(smart_query|hybrid_search_kb|crag_search|multi_hop_search|verify_answer)")',
55
+ re.IGNORECASE,
56
+ )
57
+
58
+ try:
59
+ with log_path.open("rb") as handle:
60
+ handle.seek(0, 2)
61
+ size = handle.tell()
62
+ handle.seek(max(0, size - 2_000_000))
63
+ lines = handle.read().decode("utf-8", errors="replace").splitlines()
64
+ except OSError:
65
+ sys.exit(1)
66
+
67
+ for line in lines:
68
+ if not tool_pattern.search(line):
69
+ continue
70
+ raw_ts = line.split(" ", 1)[0]
71
+ try:
72
+ ts = datetime.fromisoformat(raw_ts.replace("Z", "+00:00")).timestamp()
73
+ except ValueError:
74
+ continue
75
+ if ts >= since:
76
+ sys.exit(0)
77
+
78
+ sys.exit(1)
79
+ PY
80
+ }
81
+
82
+ if ai_toolkit_codex_log_has_search_since "$FLAG"; then
83
+ rm -f "$FLAG" 2>/dev/null
84
+ exit 0
85
+ fi
86
+
34
87
  # Read the original prompt (line 2 of the flag file) for the reminder.
35
88
  PROMPT_PREVIEW=$(sed -n '2p' "$FLAG" 2>/dev/null | head -c 200)
36
89
  rm -f "$FLAG" 2>/dev/null # one-shot; do not loop forever
package/app/hooks.json CHANGED
@@ -103,7 +103,7 @@
103
103
  "hooks": [
104
104
  {
105
105
  "type": "command",
106
- "command": "\"$HOME/.softspark/ai-toolkit/hooks/user-prompt-submit.sh\""
106
+ "command": "AI_TOOLKIT_HOOK_QUIET=1 \"$HOME/.softspark/ai-toolkit/hooks/user-prompt-submit.sh\""
107
107
  }
108
108
  ]
109
109
  },
@@ -151,7 +151,7 @@
151
151
  },
152
152
  {
153
153
  "_source": "ai-toolkit",
154
- "matcher": "mcp__rag-mcp__smart_query|mcp__rag-mcp__hybrid_search_kb|mcp__rag-mcp__crag_search|mcp__rag-mcp__multi_hop_search|mcp__rag-mcp__verify_answer|WebSearch|WebFetch",
154
+ "matcher": "mcp__.*__(smart_query|hybrid_search_kb|crag_search|multi_hop_search|verify_answer)|WebSearch|WebFetch",
155
155
  "hooks": [
156
156
  {
157
157
  "type": "command",
@@ -1,5 +1,5 @@
1
1
  {
2
- "last_run": "2026-05-12T19:04:22Z",
2
+ "last_run": "2026-05-21T08:27:23Z",
3
3
  "schema_version": 1,
4
4
  "tools": {
5
5
  "aider": {
@@ -24,17 +24,18 @@
24
24
  }
25
25
  },
26
26
  "augment": {
27
- "docs_hash": "ceaf27b7126f44dd",
27
+ "docs_hash": "8be23f4fb78816c3",
28
28
  "headings": [
29
- "Agent",
30
- "Chat",
29
+ "Code",
31
30
  "Documentation Index",
32
31
  "Introduction",
32
+ "On this page",
33
+ "Other automation",
34
+ "Review",
33
35
  "\u200bAuggie CLI",
34
- "\u200bGet started in minutes",
35
- "\u200bJetBrains IDEs",
36
- "\u200bLearn more",
37
- "\u200bVisual Studio Code"
36
+ "\u200bAutomate your SDLC",
37
+ "\u200bCosmos",
38
+ "\u200bGet started in minutes"
38
39
  ],
39
40
  "markers": {
40
41
  ".augment": true,
@@ -57,10 +58,11 @@
57
58
  }
58
59
  },
59
60
  "claude-code": {
60
- "docs_hash": "6ea2ec6ef023c1bd",
61
+ "docs_hash": "0518086bd4527849",
61
62
  "headings": [
62
- "Claude Code overview",
63
63
  "Documentation Index",
64
+ "On this page",
65
+ "Overview",
64
66
  "\u200bGet started",
65
67
  "\u200bNext steps",
66
68
  "\u200bUse Claude Code everywhere",
@@ -103,24 +105,27 @@
103
105
  "slash command": true,
104
106
  "sub-agent": true
105
107
  },
106
- "version": "2.1.139 (Claude Code)"
108
+ "version": "2.1.146 (Claude Code)"
107
109
  },
108
110
  "cline": {
109
- "docs_hash": "b59e8836b3217cdb",
111
+ "docs_hash": "c2ce2443743365fa",
110
112
  "headings": [
111
- "Cline CLI",
112
- "Cline Documentation",
113
- "Core Workflows",
114
- "Customization",
113
+ "API Reference",
114
+ "CLI",
115
+ "Cline Overview",
115
116
  "Documentation Index",
116
- "Features",
117
- "Install Cline",
118
- "MCP Servers",
119
- "Models &amp; Providers",
120
- "Quick Start",
121
- "What is Cline?",
122
- "Your First Project",
123
- "\u200bExplore the Docs",
117
+ "JetBrains Plugin",
118
+ "Kanban",
119
+ "Observability",
120
+ "On this page",
121
+ "SDK",
122
+ "Security &amp; Governance",
123
+ "Team Management",
124
+ "VS Code Extension",
125
+ "\u200bAgent Core (SDK)",
126
+ "\u200bApplications",
127
+ "\u200bEnterprise Solutions",
128
+ "\u200bOther IDE Supports",
124
129
  "\u200bWhat is Cline?"
125
130
  ],
126
131
  "markers": {
@@ -137,7 +142,7 @@
137
142
  }
138
143
  },
139
144
  "codex-cli": {
140
- "docs_hash": "c8fb328bf1954fc2",
145
+ "docs_hash": "70f184b6cdd1f765",
141
146
  "headings": [
142
147
  "About",
143
148
  "Contributing",
@@ -156,7 +161,7 @@
156
161
  "Packages 0",
157
162
  "Provide feedback",
158
163
  "Quickstart",
159
- "Releases 784",
164
+ "Releases 795",
160
165
  "Repository files navigation",
161
166
  "Resources",
162
167
  "Saved searches",
@@ -186,10 +191,10 @@
186
191
  "mcp_servers": false,
187
192
  "sandbox": true
188
193
  },
189
- "version": "codex-cli 0.130.0"
194
+ "version": "codex-cli 0.132.0"
190
195
  },
191
196
  "cursor": {
192
- "docs_hash": "787203a4eee076f7",
197
+ "docs_hash": "60edb30c9ddcdadd",
193
198
  "headings": [],
194
199
  "markers": {
195
200
  ".cursor/rules": false,
@@ -205,7 +210,7 @@
205
210
  }
206
211
  },
207
212
  "gemini-cli": {
208
- "docs_hash": "26555623f610ff8e",
213
+ "docs_hash": "c6aab087667f7717",
209
214
  "headings": [
210
215
  "Breadcrumbs",
211
216
  "Directory actions",
@@ -244,16 +249,16 @@
244
249
  }
245
250
  },
246
251
  "github-copilot": {
247
- "docs_hash": "1566c05f84f5c1a7",
252
+ "docs_hash": "ab274112faeec90f",
248
253
  "headings": [
249
254
  "About Copilot auto model selection",
250
255
  "About Copilot integrations",
251
256
  "About agent management",
252
257
  "About agent skills",
253
- "About agentic memory for GitHub Copilot",
254
258
  "About billing for GitHub Copilot in organizations and enterprises",
255
259
  "About billing for individual GitHub Copilot plans",
256
260
  "About custom agents",
261
+ "About customizing GitHub Copilot responses",
257
262
  "Articles",
258
263
  "Did you find what you needed?",
259
264
  "GitHub Copilot",
@@ -276,7 +281,7 @@
276
281
  }
277
282
  },
278
283
  "google-antigravity": {
279
- "docs_hash": "509c72e157ecb6f3",
284
+ "docs_hash": "2c48c702b9e592a7",
280
285
  "headings": [],
281
286
  "markers": {
282
287
  "AGENTS.md": false,
@@ -292,7 +297,7 @@
292
297
  }
293
298
  },
294
299
  "opencode": {
295
- "docs_hash": "c1c8ba8f6b2e7ddf",
300
+ "docs_hash": "5277673e235393f7",
296
301
  "headings": [
297
302
  "Add features",
298
303
  "Ask questions",
@@ -331,20 +336,19 @@
331
336
  }
332
337
  },
333
338
  "roo-code": {
334
- "docs_hash": "960b2e1caf562b43",
339
+ "docs_hash": "54908ae23136b646",
335
340
  "headings": [
336
341
  "A mindset for success\u200b",
337
342
  "Additional Resources\u200b",
338
343
  "Getting Started\u200b",
339
344
  "Roo Code Docs",
340
- "Tutorial &amp; Feature Videos\u200b",
341
345
  "What can Roo Code do for you\u200b"
342
346
  ],
343
347
  "markers": {
344
348
  "Code Actions": false,
345
349
  "MCP": true,
346
350
  "Orchestrator mode": false,
347
- "custom modes": true,
351
+ "custom modes": false,
348
352
  "description": true,
349
353
  "groups": false,
350
354
  "roleDefinition": false,
@@ -353,7 +357,7 @@
353
357
  }
354
358
  },
355
359
  "windsurf": {
356
- "docs_hash": "7a8a7569f81eba1b",
360
+ "docs_hash": "fa29ba621f291d81",
357
361
  "headings": [
358
362
  "Advanced",
359
363
  "App Deploys",
@@ -362,6 +366,7 @@
362
366
  "Documentation Index",
363
367
  "MCP",
364
368
  "Memories",
369
+ "On this page",
365
370
  "Recommended Plugins",
366
371
  "Terminal",
367
372
  "Usage",
@@ -3,10 +3,10 @@ title: "SOP: Release Verification"
3
3
  category: procedures
4
4
  service: ai-toolkit
5
5
  tags: [sop, verification, release, smoke-test, install, update, qa, provenance, sarif]
6
- version: "1.4.2"
6
+ version: "1.4.3"
7
7
  created: "2026-04-08"
8
- last_updated: "2026-04-29"
9
- description: "End-to-end smoke test after installing or updating @softspark/ai-toolkit — verifies CLI, install, doctor, validation, tests, eject, npm provenance attestation, SARIF audit, and per-skill permissions. Reflects the v2.8.0 supply-chain standard. v1.3.0 added the single-run npm test discipline; v1.4.0 adds v3.0.0 deep-coverage checks (--profile full, --codex-skills, breaking-change surfaces, idempotence, registry drift, live-JSON parse) and refreshes stale thresholds. v1.4.2 makes the Phase 9.4 idempotence check deterministic by sorting file paths before hashing."
8
+ last_updated: "2026-05-19"
9
+ description: "End-to-end smoke test after installing or updating @softspark/ai-toolkit — verifies CLI, install, doctor, validation, tests, eject, npm provenance attestation, SARIF audit, and per-skill permissions. Reflects the v2.8.0 supply-chain standard. v1.3.0 added the single-run npm test discipline; v1.4.0 adds v3.0.0 deep-coverage checks (--profile full, --codex-skills, breaking-change surfaces, idempotence, registry drift, live-JSON parse) and refreshes stale thresholds. v1.4.2 makes the Phase 9.4 idempotence check deterministic by sorting file paths before hashing. v1.4.3 tightens the Phase 8.4 URL pin check so the success-message count includes only entries with a `url:` field, not local `path:` entries, and documents the `sources.json` envelope shape."
10
10
  ---
11
11
 
12
12
  # SOP: Release Verification
@@ -303,11 +303,13 @@ python3 scripts/audit_skills.py --permissions | head -40
303
303
 
304
304
  ### 8.4 URL-sourced rules/hooks are checksum-pinned
305
305
 
306
+ `sources.json` is an envelope of the form `{"schema_version": 1, "rules"|"hooks": {...}}`, so the jq filter must pick the nested map before piping into the pin assertion. The URL-count in the success message ignores local `path:`-only entries — only entries with a `url:` field are pinned and counted.
307
+
306
308
  ```bash
307
309
  jq '.rules // .hooks // {}' ~/.softspark/ai-toolkit/rules/sources.json 2>/dev/null \
308
- | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; print(f'RULE PIN OK: {len(d)} URL rules, all with sha256')"
310
+ | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; url_n=sum(1 for v in d.values() if v.get('url')); print(f'RULE PIN OK: {url_n} URL rules, all with sha256')"
309
311
  jq '.hooks // {}' ~/.softspark/ai-toolkit/hooks/external/sources.json 2>/dev/null \
310
- | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; print(f'HOOK PIN OK: {len(d)} URL hooks, all with sha256')"
312
+ | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; url_n=sum(1 for v in d.values() if v.get('url')); print(f'HOOK PIN OK: {url_n} URL hooks, all with sha256')"
311
313
  ```
312
314
 
313
315
  **Verify:**
@@ -3,9 +3,9 @@ title: "AI Toolkit - Codex CLI Compatibility"
3
3
  category: reference
4
4
  service: ai-toolkit
5
5
  tags: [codex, compatibility, install, skills, hooks]
6
- version: "1.0.0"
6
+ version: "1.0.1"
7
7
  created: "2026-04-12"
8
- last_updated: "2026-04-13"
8
+ last_updated: "2026-05-21"
9
9
  description: "Reference for how ai-toolkit maps Claude-oriented skills, hooks, and plugin packs to Codex CLI."
10
10
  ---
11
11
 
@@ -110,6 +110,11 @@ This means Claude-only events such as `TaskCompleted`, `TeammateIdle`,
110
110
  `~/.codex/hooks.json` (global layer). Non-Codex events are silently skipped.
111
111
  `remove-hook` cleans both Claude and Codex targets.
112
112
 
113
+ Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. This keeps
114
+ non-blocking reminders and startup context out of the visible Codex hook output
115
+ while preserving hook side effects and blocking decisions such as search-first
116
+ Stop enforcement.
117
+
113
118
  ## Behavioral Limits
114
119
 
115
120
  Codex wrappers preserve workflow intent, but not every Claude runtime behavior
@@ -120,6 +125,10 @@ Known limits:
120
125
  - No native Codex equivalent of tmux-backed Agent Teams lifecycle events
121
126
  - No separate task object model equivalent to Claude `Task*` APIs
122
127
  - Hook event coverage is narrower than Claude Code
128
+ - MCP search tool calls may not fire the shared `PostToolUse` search tracker,
129
+ so `stop-search-check.sh` also checks `~/.codex/log/codex-tui.log` for
130
+ `smart_query`, `hybrid_search_kb`, `crag_search`, `multi_hop_search`, and
131
+ `verify_answer` calls after the search-first flag timestamp before blocking.
123
132
 
124
133
  These are runtime platform limits, not installation defects.
125
134
 
@@ -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.1"
6
+ version: "1.5.2"
7
7
  created: "2026-03-27"
8
- last_updated: "2026-05-12"
8
+ last_updated: "2026-05-21"
9
9
  description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
10
10
  ---
11
11
 
@@ -50,6 +50,11 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
50
50
  3. Loads session context from `.claude/session-context.md` (if exists)
51
51
  4. Loads active instincts from `.claude/instincts/*.md` (if any)
52
52
 
53
+ When `AI_TOOLKIT_HOOK_QUIET=1`, the hook still performs session-state reset,
54
+ stale search-flag cleanup, and update notification side effects, but suppresses
55
+ all informational stdout so runtimes such as Codex do not show startup hook
56
+ context in the UI.
57
+
53
58
  ### Notification — `notify-waiting.sh`
54
59
 
55
60
  | Field | Value |
@@ -104,7 +109,10 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
104
109
 
105
110
  **Action:** Adds a lightweight governance reminder: plan mode for architectural work, evidence-first debugging, KB-first research, and validation expectations.
106
111
 
107
- Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
112
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
113
+ registers this command with `AI_TOOLKIT_HOOK_QUIET=1`, so it still arms or
114
+ clears the per-session search-first flag but suppresses the informational
115
+ reminder output.
108
116
 
109
117
  ### UserPromptSubmit (usage tracking) — `track-usage.sh`
110
118
 
@@ -377,11 +385,11 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
377
385
  | Field | Value |
378
386
  |-------|-------|
379
387
  | Event | `PostToolUse` |
380
- | Matcher | `mcp__rag-mcp__smart_query\|mcp__rag-mcp__hybrid_search_kb\|mcp__rag-mcp__crag_search\|mcp__rag-mcp__multi_hop_search\|mcp__rag-mcp__verify_answer\|WebSearch\|WebFetch` |
388
+ | Matcher | `mcp__.*__(smart_query\|hybrid_search_kb\|crag_search\|multi_hop_search\|verify_answer)\|WebSearch\|WebFetch` |
381
389
  | Script | `~/.softspark/ai-toolkit/hooks/search-tracker.sh` |
382
390
  | Fires | After any search-style tool call |
383
391
 
384
- **Action:** Clears `~/.softspark/ai-toolkit/state/search-required-<session_id>.flag` (per-session, keyed by `session_id` from the hook stdin payload, falling back to `transcript_path` basename, then `default`). Pairs with `user-prompt-submit.sh` (sets the flag on long technical prompts only when a search provider is detected or strict mode is enabled) and `stop-search-check.sh` (blocks Stop if the calling session's flag is still set). Together they enforce the global CLAUDE.md GOLDEN RULE without breaking offline/no-RAG installs and without cross-session interference when multiple Claude Code windows run in parallel.
392
+ **Action:** Clears `~/.softspark/ai-toolkit/state/search-required-<session_id>.flag` (per-session, keyed by `session_id` from the hook stdin payload, falling back to `transcript_path` basename, then `default`). Pairs with `user-prompt-submit.sh` (sets the flag on long technical prompts only when a search provider is detected or strict mode is enabled) and `stop-search-check.sh` (blocks Stop if the calling session's flag is still set). Search provider detection parses actual MCP server names from `mcpServers`, `mcp_servers`, or `mcp` config blocks; hook matchers and permission allowlists do not count as providers. Together the hooks enforce the global CLAUDE.md GOLDEN RULE without breaking offline/no-RAG installs and without cross-session interference when multiple Claude Code windows run in parallel.
385
393
 
386
394
  Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
387
395
 
@@ -394,7 +402,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
394
402
  | Script | `~/.softspark/ai-toolkit/hooks/stop-search-check.sh` |
395
403
  | Fires | When Claude finishes a response |
396
404
 
397
- **Action:** If `search-required-<session_id>.flag` for the calling session is still present (no search tool ran during this turn) and a search provider is still detectable, emits `{"decision":"block","reason":"..."}` to continue the conversation with a search-first reminder. If no RAG/Web provider is detected, it clears the stale flag and exits 0, so offline/no-MCP users are not blocked. Flags are scoped by `session_id` from the hook stdin payload so a Stop in session B never consumes session A's flag (and vice versa). Stale per-session flags older than 60 minutes are GC'd on the next `SessionStart`.
405
+ **Action:** If `search-required-<session_id>.flag` for the calling session is still present (no search tool ran during this turn) and a search provider is still detectable, emits `{"decision":"block","reason":"..."}` to continue the conversation with a search-first reminder. If no RAG/Web provider is detected, it clears the stale flag and exits 0, so offline/no-MCP users are not blocked. On Codex, where MCP search tools may not trigger the shared `PostToolUse` tracker, the hook also checks `~/.codex/log/codex-tui.log` for search tool calls after the flag timestamp before blocking. Flags are scoped by `session_id` from the hook stdin payload so a Stop in session B never consumes session A's flag (and vice versa). Stale per-session flags older than 60 minutes are GC'd on the next `SessionStart`.
398
406
 
399
407
  **Overrides:** `CLAUDE_SKIP_SEARCH_FIRST=1`, `AI_TOOLKIT_SEARCH_FIRST=off`, or `AI_TOOLKIT_SEARCH_FIRST=strict` to force enforcement. Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
400
408
 
@@ -432,7 +440,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
432
440
  | `scripts/test_cohesion.py` | Resolves changed paths → test commands via cohesion map. First-match-wins. Stdlib-only. |
433
441
  | `app/hooks/test-cohesion-map.json` | Toolkit-default path → tests mapping (used when no project map exists). |
434
442
  | `app/hooks/_locate-toolkit.sh` | Shared bash helper that exports `$TOOLKIT_DIR` for hooks needing scripts/. |
435
- | `app/hooks/_hook-io.sh` | Shared bash helper that normalizes hook payloads across Claude, Augment, Gemini, Windsurf, and Cursor-style JSON. |
443
+ | `app/hooks/_hook-io.sh` | Shared bash helper that normalizes hook payloads across Claude, Augment, Gemini, Windsurf, and Cursor-style JSON. Honors `AI_TOOLKIT_HOOK_QUIET=1` for non-blocking context output. |
436
444
  | `app/hooks/_search-capability.sh` | Shared bash helper that enables search-first blocking only when RAG/Web is configured or strict mode is requested. |
437
445
 
438
446
  ## Runtime Profiles
@@ -449,6 +457,11 @@ Set in `.claude/settings.local.json`:
449
457
  | `standard` | All hooks (default) |
450
458
  | `strict` | Standard + mypy --strict on task completion |
451
459
 
460
+ Set `AI_TOOLKIT_HOOK_QUIET=1` on hook commands to suppress non-blocking
461
+ informational context while preserving side effects and blocking decisions.
462
+ Codex-generated hooks use this mode by default, and Claude's bundled
463
+ `UserPromptSubmit` entry uses it to avoid visible prompt hook context.
464
+
452
465
  ## Architecture
453
466
 
454
467
  ```
package/llms-full.txt CHANGED
@@ -5250,10 +5250,10 @@ title: "SOP: Release Verification"
5250
5250
  category: procedures
5251
5251
  service: ai-toolkit
5252
5252
  tags: [sop, verification, release, smoke-test, install, update, qa, provenance, sarif]
5253
- version: "1.4.2"
5253
+ version: "1.4.3"
5254
5254
  created: "2026-04-08"
5255
- last_updated: "2026-04-29"
5256
- description: "End-to-end smoke test after installing or updating @softspark/ai-toolkit — verifies CLI, install, doctor, validation, tests, eject, npm provenance attestation, SARIF audit, and per-skill permissions. Reflects the v2.8.0 supply-chain standard. v1.3.0 added the single-run npm test discipline; v1.4.0 adds v3.0.0 deep-coverage checks (--profile full, --codex-skills, breaking-change surfaces, idempotence, registry drift, live-JSON parse) and refreshes stale thresholds. v1.4.2 makes the Phase 9.4 idempotence check deterministic by sorting file paths before hashing."
5255
+ last_updated: "2026-05-19"
5256
+ description: "End-to-end smoke test after installing or updating @softspark/ai-toolkit — verifies CLI, install, doctor, validation, tests, eject, npm provenance attestation, SARIF audit, and per-skill permissions. Reflects the v2.8.0 supply-chain standard. v1.3.0 added the single-run npm test discipline; v1.4.0 adds v3.0.0 deep-coverage checks (--profile full, --codex-skills, breaking-change surfaces, idempotence, registry drift, live-JSON parse) and refreshes stale thresholds. v1.4.2 makes the Phase 9.4 idempotence check deterministic by sorting file paths before hashing. v1.4.3 tightens the Phase 8.4 URL pin check so the success-message count includes only entries with a `url:` field, not local `path:` entries, and documents the `sources.json` envelope shape."
5257
5257
  ---
5258
5258
 
5259
5259
  # SOP: Release Verification
@@ -5550,11 +5550,13 @@ python3 scripts/audit_skills.py --permissions | head -40
5550
5550
 
5551
5551
  ### 8.4 URL-sourced rules/hooks are checksum-pinned
5552
5552
 
5553
+ `sources.json` is an envelope of the form `{"schema_version": 1, "rules"|"hooks": {...}}`, so the jq filter must pick the nested map before piping into the pin assertion. The URL-count in the success message ignores local `path:`-only entries — only entries with a `url:` field are pinned and counted.
5554
+
5553
5555
  ```bash
5554
5556
  jq '.rules // .hooks // {}' ~/.softspark/ai-toolkit/rules/sources.json 2>/dev/null \
5555
- | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; print(f'RULE PIN OK: {len(d)} URL rules, all with sha256')"
5557
+ | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; url_n=sum(1 for v in d.values() if v.get('url')); print(f'RULE PIN OK: {url_n} URL rules, all with sha256')"
5556
5558
  jq '.hooks // {}' ~/.softspark/ai-toolkit/hooks/external/sources.json 2>/dev/null \
5557
- | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; print(f'HOOK PIN OK: {len(d)} URL hooks, all with sha256')"
5559
+ | python3 -c "import json, sys; d=json.load(sys.stdin) or {}; bad=[n for n,v in d.items() if v.get('url') and not v.get('sha256')]; assert not bad, f'UNPINNED: {bad}'; url_n=sum(1 for v in d.values() if v.get('url')); print(f'HOOK PIN OK: {url_n} URL hooks, all with sha256')"
5558
5560
  ```
5559
5561
 
5560
5562
  **Verify:**
@@ -6926,9 +6928,9 @@ title: "AI Toolkit - Codex CLI Compatibility"
6926
6928
  category: reference
6927
6929
  service: ai-toolkit
6928
6930
  tags: [codex, compatibility, install, skills, hooks]
6929
- version: "1.0.0"
6931
+ version: "1.0.1"
6930
6932
  created: "2026-04-12"
6931
- last_updated: "2026-04-13"
6933
+ last_updated: "2026-05-21"
6932
6934
  description: "Reference for how ai-toolkit maps Claude-oriented skills, hooks, and plugin packs to Codex CLI."
6933
6935
  ---
6934
6936
 
@@ -7033,6 +7035,11 @@ This means Claude-only events such as `TaskCompleted`, `TeammateIdle`,
7033
7035
  `~/.codex/hooks.json` (global layer). Non-Codex events are silently skipped.
7034
7036
  `remove-hook` cleans both Claude and Codex targets.
7035
7037
 
7038
+ Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. This keeps
7039
+ non-blocking reminders and startup context out of the visible Codex hook output
7040
+ while preserving hook side effects and blocking decisions such as search-first
7041
+ Stop enforcement.
7042
+
7036
7043
  ## Behavioral Limits
7037
7044
 
7038
7045
  Codex wrappers preserve workflow intent, but not every Claude runtime behavior
@@ -7043,6 +7050,10 @@ Known limits:
7043
7050
  - No native Codex equivalent of tmux-backed Agent Teams lifecycle events
7044
7051
  - No separate task object model equivalent to Claude `Task*` APIs
7045
7052
  - Hook event coverage is narrower than Claude Code
7053
+ - MCP search tool calls may not fire the shared `PostToolUse` search tracker,
7054
+ so `stop-search-check.sh` also checks `~/.codex/log/codex-tui.log` for
7055
+ `smart_query`, `hybrid_search_kb`, `crag_search`, `multi_hop_search`, and
7056
+ `verify_answer` calls after the search-first flag timestamp before blocking.
7046
7057
 
7047
7058
  These are runtime platform limits, not installation defects.
7048
7059
 
@@ -8824,9 +8835,9 @@ title: "Hooks Catalog"
8824
8835
  category: reference
8825
8836
  service: ai-toolkit
8826
8837
  tags: [hooks, quality, safety, enforcement, settings.json]
8827
- version: "1.5.1"
8838
+ version: "1.5.2"
8828
8839
  created: "2026-03-27"
8829
- last_updated: "2026-05-12"
8840
+ last_updated: "2026-05-21"
8830
8841
  description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
8831
8842
  ---
8832
8843
 
@@ -8871,6 +8882,11 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
8871
8882
  3. Loads session context from `.claude/session-context.md` (if exists)
8872
8883
  4. Loads active instincts from `.claude/instincts/*.md` (if any)
8873
8884
 
8885
+ When `AI_TOOLKIT_HOOK_QUIET=1`, the hook still performs session-state reset,
8886
+ stale search-flag cleanup, and update notification side effects, but suppresses
8887
+ all informational stdout so runtimes such as Codex do not show startup hook
8888
+ context in the UI.
8889
+
8874
8890
  ### Notification — `notify-waiting.sh`
8875
8891
 
8876
8892
  | Field | Value |
@@ -8925,7 +8941,10 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
8925
8941
 
8926
8942
  **Action:** Adds a lightweight governance reminder: plan mode for architectural work, evidence-first debugging, KB-first research, and validation expectations.
8927
8943
 
8928
- Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
8944
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
8945
+ registers this command with `AI_TOOLKIT_HOOK_QUIET=1`, so it still arms or
8946
+ clears the per-session search-first flag but suppresses the informational
8947
+ reminder output.
8929
8948
 
8930
8949
  ### UserPromptSubmit (usage tracking) — `track-usage.sh`
8931
8950
 
@@ -9198,11 +9217,11 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
9198
9217
  | Field | Value |
9199
9218
  |-------|-------|
9200
9219
  | Event | `PostToolUse` |
9201
- | Matcher | `mcp__rag-mcp__smart_query\|mcp__rag-mcp__hybrid_search_kb\|mcp__rag-mcp__crag_search\|mcp__rag-mcp__multi_hop_search\|mcp__rag-mcp__verify_answer\|WebSearch\|WebFetch` |
9220
+ | Matcher | `mcp__.*__(smart_query\|hybrid_search_kb\|crag_search\|multi_hop_search\|verify_answer)\|WebSearch\|WebFetch` |
9202
9221
  | Script | `~/.softspark/ai-toolkit/hooks/search-tracker.sh` |
9203
9222
  | Fires | After any search-style tool call |
9204
9223
 
9205
- **Action:** Clears `~/.softspark/ai-toolkit/state/search-required-<session_id>.flag` (per-session, keyed by `session_id` from the hook stdin payload, falling back to `transcript_path` basename, then `default`). Pairs with `user-prompt-submit.sh` (sets the flag on long technical prompts only when a search provider is detected or strict mode is enabled) and `stop-search-check.sh` (blocks Stop if the calling session's flag is still set). Together they enforce the global CLAUDE.md GOLDEN RULE without breaking offline/no-RAG installs and without cross-session interference when multiple Claude Code windows run in parallel.
9224
+ **Action:** Clears `~/.softspark/ai-toolkit/state/search-required-<session_id>.flag` (per-session, keyed by `session_id` from the hook stdin payload, falling back to `transcript_path` basename, then `default`). Pairs with `user-prompt-submit.sh` (sets the flag on long technical prompts only when a search provider is detected or strict mode is enabled) and `stop-search-check.sh` (blocks Stop if the calling session's flag is still set). Search provider detection parses actual MCP server names from `mcpServers`, `mcp_servers`, or `mcp` config blocks; hook matchers and permission allowlists do not count as providers. Together the hooks enforce the global CLAUDE.md GOLDEN RULE without breaking offline/no-RAG installs and without cross-session interference when multiple Claude Code windows run in parallel.
9206
9225
 
9207
9226
  Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9208
9227
 
@@ -9215,7 +9234,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9215
9234
  | Script | `~/.softspark/ai-toolkit/hooks/stop-search-check.sh` |
9216
9235
  | Fires | When Claude finishes a response |
9217
9236
 
9218
- **Action:** If `search-required-<session_id>.flag` for the calling session is still present (no search tool ran during this turn) and a search provider is still detectable, emits `{"decision":"block","reason":"..."}` to continue the conversation with a search-first reminder. If no RAG/Web provider is detected, it clears the stale flag and exits 0, so offline/no-MCP users are not blocked. Flags are scoped by `session_id` from the hook stdin payload so a Stop in session B never consumes session A's flag (and vice versa). Stale per-session flags older than 60 minutes are GC'd on the next `SessionStart`.
9237
+ **Action:** If `search-required-<session_id>.flag` for the calling session is still present (no search tool ran during this turn) and a search provider is still detectable, emits `{"decision":"block","reason":"..."}` to continue the conversation with a search-first reminder. If no RAG/Web provider is detected, it clears the stale flag and exits 0, so offline/no-MCP users are not blocked. On Codex, where MCP search tools may not trigger the shared `PostToolUse` tracker, the hook also checks `~/.codex/log/codex-tui.log` for search tool calls after the flag timestamp before blocking. Flags are scoped by `session_id` from the hook stdin payload so a Stop in session B never consumes session A's flag (and vice versa). Stale per-session flags older than 60 minutes are GC'd on the next `SessionStart`.
9219
9238
 
9220
9239
  **Overrides:** `CLAUDE_SKIP_SEARCH_FIRST=1`, `AI_TOOLKIT_SEARCH_FIRST=off`, or `AI_TOOLKIT_SEARCH_FIRST=strict` to force enforcement. Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9221
9240
 
@@ -9253,7 +9272,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9253
9272
  | `scripts/test_cohesion.py` | Resolves changed paths → test commands via cohesion map. First-match-wins. Stdlib-only. |
9254
9273
  | `app/hooks/test-cohesion-map.json` | Toolkit-default path → tests mapping (used when no project map exists). |
9255
9274
  | `app/hooks/_locate-toolkit.sh` | Shared bash helper that exports `$TOOLKIT_DIR` for hooks needing scripts/. |
9256
- | `app/hooks/_hook-io.sh` | Shared bash helper that normalizes hook payloads across Claude, Augment, Gemini, Windsurf, and Cursor-style JSON. |
9275
+ | `app/hooks/_hook-io.sh` | Shared bash helper that normalizes hook payloads across Claude, Augment, Gemini, Windsurf, and Cursor-style JSON. Honors `AI_TOOLKIT_HOOK_QUIET=1` for non-blocking context output. |
9257
9276
  | `app/hooks/_search-capability.sh` | Shared bash helper that enables search-first blocking only when RAG/Web is configured or strict mode is requested. |
9258
9277
 
9259
9278
  ## Runtime Profiles
@@ -9270,6 +9289,11 @@ Set in `.claude/settings.local.json`:
9270
9289
  | `standard` | All hooks (default) |
9271
9290
  | `strict` | Standard + mypy --strict on task completion |
9272
9291
 
9292
+ Set `AI_TOOLKIT_HOOK_QUIET=1` on hook commands to suppress non-blocking
9293
+ informational context while preserving side effects and blocking decisions.
9294
+ Codex-generated hooks use this mode by default, and Claude's bundled
9295
+ `UserPromptSubmit` entry uses it to avoid visible prompt hook context.
9296
+
9273
9297
  ## Architecture
9274
9298
 
9275
9299
  ```
package/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.3.1",
2
+ "version": "4.3.2",
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": "22 global hook entries across 12 lifecycle events + 5 skill-scoped lifecycle hooks",
19
+ "description": "28 hook entries across 14 lifecycle events",
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softspark/ai-toolkit",
3
- "version": "4.3.1",
3
+ "version": "4.3.2",
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",
@@ -24,7 +24,7 @@ import sys
24
24
  from pathlib import Path
25
25
 
26
26
 
27
- HOOKS_PREFIX = '"$HOME/.softspark/ai-toolkit/hooks/'
27
+ HOOKS_PREFIX = 'AI_TOOLKIT_HOOK_QUIET=1 "$HOME/.softspark/ai-toolkit/hooks/'
28
28
 
29
29
  # Hooks compatible with Codex, grouped by event.
30
30
  # Format: (matcher, script_name)