@softspark/ai-toolkit 4.3.1 → 4.3.3

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,65 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v4.3.3 - silent hook context roll-forward (2026-05-21)
11
+
12
+ Patch release. Rolls forward the quiet-hook release with a stricter default: non-blocking plain-text hook context is now silent even when a runtime uses a stale or manually copied command without `AI_TOOLKIT_HOOK_QUIET=1`.
13
+
14
+ ### Fixed
15
+
16
+ - **Silent plain-text context by default** - non-blocking hook context output now requires `AI_TOOLKIT_HOOK_VERBOSE=1` in plain-text mode, so prompt-submit and startup reminders do not leak into the visible chat window.
17
+ - **SessionStart default output** - `session-start.sh` keeps session-state reset, stale search-flag cleanup, and update-notification side effects, but no longer prints startup reminders or loaded context unless verbose mode is enabled.
18
+
19
+ ### Changed
20
+
21
+ - **Hook output helper** - `_hook-io.sh` supports `AI_TOOLKIT_HOOK_VERBOSE=1` for local debugging while keeping plain-text context silent by default.
22
+ - **Runtime hook docs** - `kb/reference/hooks-catalog.md` and `kb/reference/codex-cli-compatibility.md` document the new silent-by-default behavior and verbose opt-in.
23
+
24
+ ### Tests
25
+
26
+ - **Silent default coverage** - `tests/test_hooks.bats` now verifies default silence for `SessionStart` and `UserPromptSubmit`, plus verbose opt-in for the same context messages.
27
+
28
+ ### Verification
29
+
30
+ - `npm test` - 1144 passing.
31
+ - `python3 scripts/validate.py --strict` - passed.
32
+
33
+ ---
34
+
35
+ ## v4.3.2 - quiet hooks and no-RAG search-first hardening (2026-05-21)
36
+
37
+ Patch release. Fixes noisy lifecycle hook output in Codex and Claude prompt-submit flows while preserving search-first enforcement and blocking decisions.
38
+
39
+ ### Fixed
40
+
41
+ - **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.
42
+ - **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.
43
+ - **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.
44
+ - **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.
45
+
46
+ ### Changed
47
+
48
+ - **Hook output helper** - `_hook-io.sh` supports `AI_TOOLKIT_HOOK_QUIET=1` for non-blocking context output.
49
+ - **Runtime hook docs** - `kb/reference/hooks-catalog.md` and `kb/reference/codex-cli-compatibility.md` document quiet mode and the Codex search-first fallback.
50
+ - **Manifest hook count** - `manifest.json` now describes the current 28 hook entries across 14 lifecycle events.
51
+
52
+ ### Tests
53
+
54
+ - **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.
55
+ - **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.
56
+
57
+ ### Ecosystem
58
+
59
+ - **Snapshot refresh** - `benchmarks/ecosystem-doctor-snapshot.json` refreshed after class A/C upstream documentation and version drift review. No generator contract changes were required.
60
+
61
+ ### Verification
62
+
63
+ - `npm test` - 1142 passing.
64
+ - `python3 scripts/validate.py --strict` - passed.
65
+ - `python3 scripts/audit_skills.py --ci` - passed with 0 HIGH / 0 WARN.
66
+
67
+ ---
68
+
10
69
  ## v4.3.1 - per-session search-first flag (2026-05-19)
11
70
 
12
71
  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,16 @@
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-1144%20passing-success)](tests/)
10
10
 
11
- ## What's New in v4.3.1
11
+ ## What's New in v4.3.3
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. Rolls forward quiet hook handling so informational hook context stays out of the visible chat window even with stale or manually copied hook commands.
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
+ - **Silent hook context by default**: `SessionStart`, `UserPromptSubmit`, and other non-blocking plain-text context output now require `AI_TOOLKIT_HOOK_VERBOSE=1`.
16
+ - **Side effects preserved**: search-first flags, session-state reset, stale-flag cleanup, and blocking decisions still run without printing reminder text.
17
+ - **Runtime refresh applied**: installed hook scripts and Codex/Claude hook config pick up the silent default.
18
+ - **Test coverage updated**: hook tests now cover default silence and verbose opt-in, bringing the suite to 1144 tests.
19
19
 
20
20
  See [CHANGELOG.md](CHANGELOG.md) for full history.
21
21
 
@@ -125,7 +125,7 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
125
125
  | `skills/` (hybrid) | 30 | Slash commands with agent knowledge base |
126
126
  | `skills/` (knowledge) | 45 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
127
127
  | `agents/` | 44 | Specialized agents across 10 categories |
128
- | `hooks/` | 22 global + 5 skill-scoped | Quality gates, path safety, prompt governance, session lifecycle |
128
+ | `hooks/` | 28 entries / 14 events | Quality gates, path safety, prompt governance, session lifecycle |
129
129
  | `plugins/` | 11 packs | Opt-in domain bundles (security, research, frontend, enterprise, 6 language packs) |
130
130
  | `constitution.md` | 6 articles | Machine-enforced safety rules |
131
131
  | `rules/` | auto-injected | Language-specific and custom rules injected into your configs |
@@ -148,7 +148,7 @@ ai-toolkit/
148
148
  │ └── ARCHITECTURE.md # Full system design
149
149
  ├── kb/ # Reference docs, procedures, plans
150
150
  ├── scripts/ # Validation, install, evaluation scripts
151
- ├── tests/ # Bats test suite (1133 tests)
151
+ ├── tests/ # Bats test suite (1144 tests)
152
152
  └── CHANGELOG.md
153
153
  ```
154
154
 
@@ -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.3",
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,10 +58,13 @@ 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}'
64
- else
67
+ elif [ "${AI_TOOLKIT_HOOK_VERBOSE:-0}" = "1" ]; then
65
68
  printf '%s\n' "$message"
66
69
  fi
67
70
  }
@@ -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
+ [ "${AI_TOOLKIT_HOOK_QUIET:-0}" = "1" ] && return 0
12
+ [ "${AI_TOOLKIT_HOOK_VERBOSE:-0}" != "1" ] && return 0
13
+ printf '%s\n' "$1"
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" ] && [ "${AI_TOOLKIT_HOOK_VERBOSE:-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" ] && [ "${AI_TOOLKIT_HOOK_VERBOSE:-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.2"
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,15 @@ 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
+
118
+ Plain-text informational hook context is also silent by default in the shared
119
+ hook helper. Set `AI_TOOLKIT_HOOK_VERBOSE=1` only when debugging hook output
120
+ outside the Codex UI.
121
+
113
122
  ## Behavioral Limits
114
123
 
115
124
  Codex wrappers preserve workflow intent, but not every Claude runtime behavior
@@ -120,6 +129,10 @@ Known limits:
120
129
  - No native Codex equivalent of tmux-backed Agent Teams lifecycle events
121
130
  - No separate task object model equivalent to Claude `Task*` APIs
122
131
  - Hook event coverage is narrower than Claude Code
132
+ - MCP search tool calls may not fire the shared `PostToolUse` search tracker,
133
+ so `stop-search-check.sh` also checks `~/.codex/log/codex-tui.log` for
134
+ `smart_query`, `hybrid_search_kb`, `crag_search`, `multi_hop_search`, and
135
+ `verify_answer` calls after the search-first flag timestamp before blocking.
123
136
 
124
137
  These are runtime platform limits, not installation defects.
125
138
 
@@ -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.3"
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
+ By default the hook performs session-state reset, stale search-flag cleanup, and
54
+ update notification side effects without printing informational stdout. Set
55
+ `AI_TOOLKIT_HOOK_VERBOSE=1` to print the startup reminders and loaded context
56
+ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
57
+
53
58
  ### Notification — `notify-waiting.sh`
54
59
 
55
60
  | Field | Value |
@@ -102,9 +107,16 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
102
107
  | Script | `~/.softspark/ai-toolkit/hooks/user-prompt-submit.sh` |
103
108
  | Fires | Before Claude starts working on a submitted prompt |
104
109
 
105
- **Action:** Adds a lightweight governance reminder: plan mode for architectural work, evidence-first debugging, KB-first research, and validation expectations.
110
+ **Action:** Maintains the per-session search-first flag used by Stop enforcement
111
+ and can provide a lightweight governance reminder: plan mode for architectural
112
+ work, evidence-first debugging, KB-first research, and validation expectations.
106
113
 
107
- Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
114
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
115
+ registers this command with `AI_TOOLKIT_HOOK_QUIET=1`, so it still arms or
116
+ clears the per-session search-first flag but suppresses the informational
117
+ reminder output. In plain-text mode, informational reminders are silent by
118
+ default and require `AI_TOOLKIT_HOOK_VERBOSE=1`; JSON hook output remains
119
+ available with `AI_TOOLKIT_HOOK_FORMAT=json`.
108
120
 
109
121
  ### UserPromptSubmit (usage tracking) — `track-usage.sh`
110
122
 
@@ -377,11 +389,11 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
377
389
  | Field | Value |
378
390
  |-------|-------|
379
391
  | 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` |
392
+ | Matcher | `mcp__.*__(smart_query\|hybrid_search_kb\|crag_search\|multi_hop_search\|verify_answer)\|WebSearch\|WebFetch` |
381
393
  | Script | `~/.softspark/ai-toolkit/hooks/search-tracker.sh` |
382
394
  | Fires | After any search-style tool call |
383
395
 
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.
396
+ **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
397
 
386
398
  Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
387
399
 
@@ -394,7 +406,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
394
406
  | Script | `~/.softspark/ai-toolkit/hooks/stop-search-check.sh` |
395
407
  | Fires | When Claude finishes a response |
396
408
 
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`.
409
+ **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
410
 
399
411
  **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
412
 
@@ -432,7 +444,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
432
444
  | `scripts/test_cohesion.py` | Resolves changed paths → test commands via cohesion map. First-match-wins. Stdlib-only. |
433
445
  | `app/hooks/test-cohesion-map.json` | Toolkit-default path → tests mapping (used when no project map exists). |
434
446
  | `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. |
447
+ | `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` and `AI_TOOLKIT_HOOK_VERBOSE=1` for non-blocking context output. |
436
448
  | `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
449
 
438
450
  ## Runtime Profiles
@@ -449,6 +461,12 @@ Set in `.claude/settings.local.json`:
449
461
  | `standard` | All hooks (default) |
450
462
  | `strict` | Standard + mypy --strict on task completion |
451
463
 
464
+ Non-blocking informational context is silent in plain-text mode by default while
465
+ side effects and blocking decisions still run. Set `AI_TOOLKIT_HOOK_VERBOSE=1`
466
+ only when debugging hook context locally. `AI_TOOLKIT_HOOK_QUIET=1` keeps hook
467
+ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
468
+ `UserPromptSubmit` entry use it to avoid visible prompt hook context.
469
+
452
470
  ## Architecture
453
471
 
454
472
  ```
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.2"
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,15 @@ 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
+
7043
+ Plain-text informational hook context is also silent by default in the shared
7044
+ hook helper. Set `AI_TOOLKIT_HOOK_VERBOSE=1` only when debugging hook output
7045
+ outside the Codex UI.
7046
+
7036
7047
  ## Behavioral Limits
7037
7048
 
7038
7049
  Codex wrappers preserve workflow intent, but not every Claude runtime behavior
@@ -7043,6 +7054,10 @@ Known limits:
7043
7054
  - No native Codex equivalent of tmux-backed Agent Teams lifecycle events
7044
7055
  - No separate task object model equivalent to Claude `Task*` APIs
7045
7056
  - Hook event coverage is narrower than Claude Code
7057
+ - MCP search tool calls may not fire the shared `PostToolUse` search tracker,
7058
+ so `stop-search-check.sh` also checks `~/.codex/log/codex-tui.log` for
7059
+ `smart_query`, `hybrid_search_kb`, `crag_search`, `multi_hop_search`, and
7060
+ `verify_answer` calls after the search-first flag timestamp before blocking.
7046
7061
 
7047
7062
  These are runtime platform limits, not installation defects.
7048
7063
 
@@ -8824,9 +8839,9 @@ title: "Hooks Catalog"
8824
8839
  category: reference
8825
8840
  service: ai-toolkit
8826
8841
  tags: [hooks, quality, safety, enforcement, settings.json]
8827
- version: "1.5.1"
8842
+ version: "1.5.3"
8828
8843
  created: "2026-03-27"
8829
- last_updated: "2026-05-12"
8844
+ last_updated: "2026-05-21"
8830
8845
  description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
8831
8846
  ---
8832
8847
 
@@ -8871,6 +8886,11 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
8871
8886
  3. Loads session context from `.claude/session-context.md` (if exists)
8872
8887
  4. Loads active instincts from `.claude/instincts/*.md` (if any)
8873
8888
 
8889
+ By default the hook performs session-state reset, stale search-flag cleanup, and
8890
+ update notification side effects without printing informational stdout. Set
8891
+ `AI_TOOLKIT_HOOK_VERBOSE=1` to print the startup reminders and loaded context
8892
+ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
8893
+
8874
8894
  ### Notification — `notify-waiting.sh`
8875
8895
 
8876
8896
  | Field | Value |
@@ -8923,9 +8943,16 @@ ai-toolkit update # re-copies scripts, re-merges (idempotent)
8923
8943
  | Script | `~/.softspark/ai-toolkit/hooks/user-prompt-submit.sh` |
8924
8944
  | Fires | Before Claude starts working on a submitted prompt |
8925
8945
 
8926
- **Action:** Adds a lightweight governance reminder: plan mode for architectural work, evidence-first debugging, KB-first research, and validation expectations.
8946
+ **Action:** Maintains the per-session search-first flag used by Stop enforcement
8947
+ and can provide a lightweight governance reminder: plan mode for architectural
8948
+ work, evidence-first debugging, KB-first research, and validation expectations.
8927
8949
 
8928
- Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
8950
+ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
8951
+ registers this command with `AI_TOOLKIT_HOOK_QUIET=1`, so it still arms or
8952
+ clears the per-session search-first flag but suppresses the informational
8953
+ reminder output. In plain-text mode, informational reminders are silent by
8954
+ default and require `AI_TOOLKIT_HOOK_VERBOSE=1`; JSON hook output remains
8955
+ available with `AI_TOOLKIT_HOOK_FORMAT=json`.
8929
8956
 
8930
8957
  ### UserPromptSubmit (usage tracking) — `track-usage.sh`
8931
8958
 
@@ -9198,11 +9225,11 @@ First-match-wins per file. Built-in runners: `bats`, `pytest`, `vitest`, `jest`.
9198
9225
  | Field | Value |
9199
9226
  |-------|-------|
9200
9227
  | 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` |
9228
+ | Matcher | `mcp__.*__(smart_query\|hybrid_search_kb\|crag_search\|multi_hop_search\|verify_answer)\|WebSearch\|WebFetch` |
9202
9229
  | Script | `~/.softspark/ai-toolkit/hooks/search-tracker.sh` |
9203
9230
  | Fires | After any search-style tool call |
9204
9231
 
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.
9232
+ **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
9233
 
9207
9234
  Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9208
9235
 
@@ -9215,7 +9242,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9215
9242
  | Script | `~/.softspark/ai-toolkit/hooks/stop-search-check.sh` |
9216
9243
  | Fires | When Claude finishes a response |
9217
9244
 
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`.
9245
+ **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
9246
 
9220
9247
  **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
9248
 
@@ -9253,7 +9280,7 @@ Non-blocking (exit 0). Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
9253
9280
  | `scripts/test_cohesion.py` | Resolves changed paths → test commands via cohesion map. First-match-wins. Stdlib-only. |
9254
9281
  | `app/hooks/test-cohesion-map.json` | Toolkit-default path → tests mapping (used when no project map exists). |
9255
9282
  | `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. |
9283
+ | `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` and `AI_TOOLKIT_HOOK_VERBOSE=1` for non-blocking context output. |
9257
9284
  | `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
9285
 
9259
9286
  ## Runtime Profiles
@@ -9270,6 +9297,12 @@ Set in `.claude/settings.local.json`:
9270
9297
  | `standard` | All hooks (default) |
9271
9298
  | `strict` | Standard + mypy --strict on task completion |
9272
9299
 
9300
+ Non-blocking informational context is silent in plain-text mode by default while
9301
+ side effects and blocking decisions still run. Set `AI_TOOLKIT_HOOK_VERBOSE=1`
9302
+ only when debugging hook context locally. `AI_TOOLKIT_HOOK_QUIET=1` keeps hook
9303
+ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
9304
+ `UserPromptSubmit` entry use it to avoid visible prompt hook context.
9305
+
9273
9306
  ## Architecture
9274
9307
 
9275
9308
  ```
package/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.3.1",
2
+ "version": "4.3.3",
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.3",
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)