@softspark/ai-toolkit 4.4.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,50 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v4.5.0 - Unicode-safety scanner, loop guard, honest instincts (2026-06-02)
11
+
12
+ Minor release. Hardens the security audit against invisible prompt injection, adds a repeated-action loop guard, fixes destructive-guard false positives, and turns the instinct system from a dormant promise into a working manual feature.
13
+
14
+ ### Added
15
+ - **Unicode-safety scanner** — `scripts/audit_skills.py` now flags invisible/smuggled Unicode across shipped prompt text (skills, agents, rules, personas, mcp-templates): tag-block ASCII smuggling (`U+E0000–E007F`) and Trojan Source bidi controls as HIGH, zero-width/invisible format chars as WARN. Emoji ZWJ (`U+200D`) is allowlisted. Runs inside the existing `--ci` gate.
16
+ - **`loop-guard.sh`** — advisory `PostToolUse` hook (`Bash|Edit|MultiEdit|Write`) that warns when the same action repeats within a short window, catching successful-but-identical loops the `/repeat` circuit breaker (failures-only) misses. Edits track content, so iterative editing of one file does not trip it. Tunable via `AI_TOOLKIT_LOOP_WINDOW`/`AI_TOOLKIT_LOOP_THRESHOLD`. Hook entries: 28 → 29.
17
+ - **Per-hook opt-out** — `AI_TOOLKIT_DISABLED_HOOKS` (comma list) disables named profile-gated hooks via `_profile-check.sh`. Safety guards are intentionally excluded — remove them with `ai-toolkit remove-hook`.
18
+ - **Editor hooks honesty** — the README platform matrix gained a **Hooks** column marking which editors get lifecycle hook enforcement; `validate.py` cross-checks the claim against the actual `generate_*_hooks.py` generators and fails on drift.
19
+ - **`doctor` language-rules drift check** — warns when a local-install project gained a language (e.g. a new `Cargo.toml`) whose `<lang>-rules` were never injected.
20
+ - **Live-app rubric verification** — `verification-before-completion` documents an optional weighted-rubric scoring pass for behavioral/visual work.
21
+
22
+ ### Changed
23
+ - **Instincts load by default** — `session-start.sh` loads `.claude/instincts/*.md` whenever present (previously gated behind `AI_TOOLKIT_HOOK_VERBOSE=1`, so they never surfaced by default). `AI_TOOLKIT_HOOK_QUIET=1` suppresses; no instincts on disk means no output.
24
+ - **memory-pack `strip_private.py`** — now redacts high-confidence secrets (API keys, tokens, private keys) to `[REDACTED:<label>]` in addition to stripping `<private>` blocks before SQLite storage.
25
+
26
+ ### Fixed
27
+ - **`guard-destructive.sh` false positives** — `git push --force-with-lease`/`--force-if-includes` are no longer blocked, and a single non-chained `echo`/`printf`/`git commit`/`git tag` carrying a destructive token as data (e.g. a commit message mentioning `DROP TABLE`) passes. Chained commands (`&&`, `||`, `;`, `|`) and real executions (e.g. `psql -c "DROP TABLE"`) are still inspected and blocked.
28
+ - **`instinct-review` documentation** — removed the false claim of an automatic session-end instinct extractor that never existed; the skill now documents the real manual authoring + curation flow.
29
+
30
+ Test count: 1151 → 1179. No skill/agent count change.
31
+
32
+ ---
33
+
34
+ ## v4.4.2 - Ecosystem sync: Claude Code 2.1.158 + Codex 0.134 hook events (2026-05-30)
35
+
36
+ Patch release. Syncs the tool registry and `hook-creator` skill with newly detected upstream hook events and refreshes the ecosystem drift snapshot. No generated output or runtime behavior changes.
37
+
38
+ ### Changed
39
+
40
+ - **Claude Code hook events** - Recorded `MessageDisplay` (new in Claude Code 2.1.152) in `scripts/ecosystem_tools.json` and the `hook-creator` skill's Supported Hook Events table. Also added three real-but-untracked events to the registry: `PostToolUseFailure`, `PostToolBatch`, `UserPromptExpansion`.
41
+ - **Codex hook events** - Recorded the four Codex events we did not track (`PreCompact`, `PostCompact`, `SubagentStart`, `SubagentStop`); Codex exposes 10 lifecycle events. Updated the `scripts/generate_codex_hooks.py` docstring (6 to 10) and `kb/reference/supported-tools-registry.md`.
42
+ - **Ecosystem snapshot** - Refreshed `benchmarks/ecosystem-doctor-snapshot.json` to baseline Claude Code 2.1.158 and Codex 0.134, and bumped the registry `last_updated`.
43
+
44
+ ### Ecosystem
45
+
46
+ - Class-B drift (new Claude Code and Codex hook events) tracked in the registry and skill docs; wiring the Codex subagent/compaction events into generated `.codex/hooks.json` is deferred to a future release. GitHub Copilot docs reorg classified class C (not adopted). Seven editors showed cosmetic-only doc drift (class A).
47
+
48
+ ### Verification
49
+
50
+ - `python3 scripts/validate.py --strict`
51
+ - `python3 scripts/ecosystem_doctor.py --offline --check`
52
+ - `npm test` (1151 passing)
53
+
10
54
  ## v4.4.1 - Codex hook output compatibility fix (2026-05-25)
11
55
 
12
56
  Patch release. Fixes Codex `UserPromptSubmit` hook JSON validation failures and visible hook-context noise while preserving hook side effects.
package/README.md CHANGED
@@ -6,17 +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-1151%20passing-success)](tests/)
9
+ [![Tests](https://img.shields.io/badge/tests-1179%20passing-success)](tests/)
10
10
 
11
- ## What's New in v4.4.1
11
+ ## What's New in v4.5.0
12
12
 
13
- Patch release. Fixes Codex `UserPromptSubmit` hook output validation and visible hook-context noise while preserving hook side effects.
13
+ Minor release. Hardens the security audit against invisible prompt injection, adds a repeated-action loop guard, fixes destructive-guard false positives, and makes the instinct system actually work.
14
14
 
15
- - **Codex-safe prompt hook defaults**: generated Codex hooks keep `UserPromptSubmit` side effects quiet without emitting visible `additionalContext` in the TUI.
16
- - **Event-specific hook context**: JSON context output now includes `hookSpecificOutput.hookEventName` when enabled, matching Codex's event-specific schema.
17
- - **Silent best-effort stats**: `track-usage.sh` no longer leaks Python tracebacks when local stats writes are blocked.
18
- - **Sandbox-safe search flags**: search-first flag write failures no longer corrupt JSON hook output.
19
- - **Release coverage updated**: hook regression coverage now includes blocked state and stats writes; suite count is 1151 tests.
15
+ - **Unicode-safety scanner**: the skill/agent audit now flags invisible and smuggled Unicode (tag-block ASCII smuggling, Trojan Source bidi controls) across all shipped prompt text — a prompt-injection vector regex checks never caught. Runs in the `--ci` gate.
16
+ - **Loop guard**: a new advisory `PostToolUse` hook warns when the same action repeats, catching stuck loops that the `/repeat` failure-counter circuit breaker misses.
17
+ - **`git push --force-with-lease` unblocked**: the destructive-command guard no longer false-positives on safe force-pushes or on commit messages that merely mention `DROP TABLE`/`rm -rf`.
18
+ - **Instincts load by default**: hand-authored `.claude/instincts/*.md` now load at session start (previously dormant behind a verbose flag). The skill docs were corrected to drop a never-implemented auto-extractor claim.
19
+ - **Editor honesty + secret scrubbing**: the platform matrix marks which editors get hook enforcement, and memory-pack now redacts secrets before storing session observations.
20
20
 
21
21
  See [CHANGELOG.md](CHANGELOG.md) for full history.
22
22
 
@@ -99,22 +99,22 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
99
99
 
100
100
  ## Platform Support
101
101
 
102
- | Platform | Config Files | Scope |
103
- |----------|-------------|-------|
104
- | Claude Code | `~/.claude/` | global |
105
- | Cursor | `.cursor/rules/*.mdc` + `.cursor/mcp.json` + `.cursor/skills/*` | project (`~/.cursor/mcp.json` for MCP only) |
106
- | Windsurf | `~/.codeium/.../global_rules.md` + `~/.codeium/windsurf/skills/*` + `.windsurf/rules/*.md` | global + project |
107
- | Gemini CLI | `~/.gemini/GEMINI.md` | global |
108
- | GitHub Copilot | `.github/copilot-instructions.md` | project |
109
- | Cline | `~/.cline/rules/*.md` + `~/.cline/skills/*` + `.clinerules/*.md` | global + project |
110
- | Roo Code | `~/.roo/rules/*.md` + `.roomodes` + `.roo/rules/*.md` | global rules + project |
111
- | Aider | `~/.aider.conf.yml` + `.aider.conf.yml` + `CONVENTIONS.md` | global + project |
112
- | Augment | `~/.augment/rules/*.md` + `.augment/rules/ai-toolkit-*.md` | global + project |
113
- | Google Antigravity | `.agent/rules/*.md` + `.agent/workflows/*.md` | project |
114
- | Codex CLI | `AGENTS.md` + `.agents/rules/*.md` + `.agents/skills/*` + `.codex/hooks.json` | project + global plugin |
115
- | opencode | `AGENTS.md` + `.opencode/{agents,commands,plugins}/*` + `opencode.json` | project + global (`~/.config/opencode/`) |
116
-
117
- > Claude Code is always installed (primary platform). Other editors on demand with `--editors`. All platforms receive the same agent/skill catalog, guidelines, and registered custom rules.
102
+ | Platform | Config Files | Hooks | Scope |
103
+ |----------|-------------|:-----:|-------|
104
+ | Claude Code | `~/.claude/` | ✅ | global |
105
+ | Cursor | `.cursor/rules/*.mdc` + `.cursor/mcp.json` + `.cursor/skills/*` | ✅ | project (`~/.cursor/mcp.json` for MCP only) |
106
+ | Windsurf | `~/.codeium/.../global_rules.md` + `~/.codeium/windsurf/skills/*` + `.windsurf/rules/*.md` | ✅ | global + project |
107
+ | Gemini CLI | `~/.gemini/GEMINI.md` | ✅ | global |
108
+ | GitHub Copilot | `.github/copilot-instructions.md` | — | project |
109
+ | Cline | `~/.cline/rules/*.md` + `~/.cline/skills/*` + `.clinerules/*.md` | — | global + project |
110
+ | Roo Code | `~/.roo/rules/*.md` + `.roomodes` + `.roo/rules/*.md` | — | global rules + project |
111
+ | Aider | `~/.aider.conf.yml` + `.aider.conf.yml` + `CONVENTIONS.md` | — | global + project |
112
+ | Augment | `~/.augment/rules/*.md` + `.augment/rules/ai-toolkit-*.md` | ✅ | global + project |
113
+ | Google Antigravity | `.agent/rules/*.md` + `.agent/workflows/*.md` | — | project |
114
+ | Codex CLI | `AGENTS.md` + `.agents/rules/*.md` + `.agents/skills/*` + `.codex/hooks.json` | ✅ | project + global plugin |
115
+ | opencode | `AGENTS.md` + `.opencode/{agents,commands,plugins}/*` + `opencode.json` | ✅ | project + global (`~/.config/opencode/`) |
116
+
117
+ > Claude Code is always installed (primary platform). Other editors on demand with `--editors`. Every platform receives the agent/skill catalog, guidelines, and registered custom rules as text. The **Hooks** column marks platforms that also get lifecycle hook enforcement — the machine-enforced constitution (guard-destructive, quality gates, search-first discipline). Platforms marked — receive those rules as guidance only, without blocking hooks.
118
118
 
119
119
  ---
120
120
 
@@ -126,7 +126,7 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
126
126
  | `skills/` (hybrid) | 30 | Slash commands with agent knowledge base |
127
127
  | `skills/` (knowledge) | 45 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
128
128
  | `agents/` | 44 | Specialized agents across 10 categories |
129
- | `hooks/` | 28 entries / 14 events | Quality gates, path safety, prompt governance, session lifecycle |
129
+ | `hooks/` | 29 entries / 14 events | Quality gates, path safety, prompt governance, loop guard, session lifecycle |
130
130
  | `plugins/` | 11 packs | Opt-in domain bundles (security, research, frontend, enterprise, 6 language packs) |
131
131
  | `constitution.md` | 6 articles | Machine-enforced safety rules |
132
132
  | `rules/` | auto-injected | Language-specific and custom rules injected into your configs |
@@ -142,14 +142,14 @@ ai-toolkit/
142
142
  │ ├── agents/ # 44 agent definitions
143
143
  │ ├── skills/ # 107 skills (task / hybrid / knowledge)
144
144
  │ ├── rules/ # Auto-injected into your CLAUDE.md
145
- │ ├── hooks/ # Hook scripts (28 entries, 14 lifecycle events)
145
+ │ ├── hooks/ # Hook scripts (29 entries, 14 lifecycle events)
146
146
  │ ├── plugins/ # 11 experimental plugin packs (opt-in)
147
147
  │ ├── output-styles/ # System prompt output style overrides
148
148
  │ ├── constitution.md # 6 immutable safety articles
149
149
  │ └── ARCHITECTURE.md # Full system design
150
150
  ├── kb/ # Reference docs, procedures, plans
151
151
  ├── scripts/ # Validation, install, evaluation scripts
152
- ├── tests/ # Bats test suite (1151 tests)
152
+ ├── tests/ # Bats test suite (1179 tests)
153
153
  └── CHANGELOG.md
154
154
  ```
155
155
 
@@ -161,7 +161,7 @@ ai-toolkit/
161
161
 
162
162
  **Machine-enforced constitution** — 6-article safety constitution enforced via `PreToolUse` hooks that actually block `rm -rf`, `DROP TABLE`, and irreversible operations. Not just documentation.
163
163
 
164
- **28 lifecycle hooks** — Executable scripts across 14 events (SessionStart → SessionEnd, plus InstructionsLoaded + ConfigChange). Guards, governance, quality gates, session persistence, MCP health checks, revert protection, test-cohesion enforcement, search-first discipline. See [Hooks Catalog](kb/reference/hooks-catalog.md).
164
+ **29 lifecycle hooks** — Executable scripts across 14 events (SessionStart → SessionEnd, plus InstructionsLoaded + ConfigChange). Guards, governance, quality gates, session persistence, MCP health checks, revert protection, test-cohesion enforcement, loop guard, search-first discipline. See [Hooks Catalog](kb/reference/hooks-catalog.md).
165
165
 
166
166
  **Security scanning** — `/skill-audit` for code-level risks, `/cve-scan` for dependency CVEs. Both CI-ready with exit codes.
167
167
 
@@ -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.4.1",
4
+ "version": "4.5.0",
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 | 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) |
11
+ | Hooks | 14 events / 29 entries (SessionStart ×3, Notification ×1, PreToolUse ×5, UserPromptSubmit ×2, PostToolUse ×5, Stop ×4, TaskCompleted ×1, TeammateIdle ×1, SubagentStart ×1, SubagentStop ×1, PreCompact ×2, SessionEnd ×1, InstructionsLoaded ×1, ConfigChange ×1) |
12
12
 
13
13
  ---
14
14
 
@@ -9,3 +9,20 @@
9
9
 
10
10
  PROFILE="${TOOLKIT_HOOK_PROFILE:-standard}"
11
11
  [ "$PROFILE" = "minimal" ] && exit 0
12
+
13
+ # Per-hook soft opt-out: AI_TOOLKIT_DISABLED_HOOKS is a comma-separated list of
14
+ # hook names (with or without the .sh suffix). A listed hook exits 0 (no-op).
15
+ # Only hooks that source this file are covered — the safety guards
16
+ # (guard-destructive/path/config) intentionally do not, and must be removed
17
+ # deliberately with `ai-toolkit remove-hook` rather than silently env-disabled.
18
+ if [ -n "${AI_TOOLKIT_DISABLED_HOOKS:-}" ]; then
19
+ _hook_name="$(basename "${BASH_SOURCE[1]:-$0}" .sh)"
20
+ IFS=',' read -ra _disabled_hooks <<< "$AI_TOOLKIT_DISABLED_HOOKS"
21
+ for _d in "${_disabled_hooks[@]}"; do
22
+ _d="${_d// /}"
23
+ _d="${_d%.sh}"
24
+ if [ -n "$_d" ] && [ "$_d" = "$_hook_name" ]; then
25
+ exit 0
26
+ fi
27
+ done
28
+ fi
@@ -18,6 +18,24 @@ fi
18
18
  # Normalize command for matching: collapse whitespace, strip backslash escapes
19
19
  NORMALIZED=$(printf '%s' "$COMMAND" | tr -s '[:space:]' ' ' | sed 's/\\//g')
20
20
 
21
+ # Benign data contexts: a single, non-chained command whose program only PRINTS
22
+ # or RECORDS text (echo/printf) or writes a commit/tag message (git commit/tag)
23
+ # cannot itself execute a destructive op — the dangerous tokens are data, not
24
+ # actions. Skip matching so "git commit -m 'fix DROP TABLE race'" is not blocked.
25
+ # Bail out of the allowlist when a command separator is present (&&, ||, ;, |) so
26
+ # chained commands like `git commit -m x && rm -rf /tmp` are still inspected.
27
+ if ! printf '%s' "$NORMALIZED" | grep -qE '(&&|\|\||;|\|)'; then
28
+ if printf '%s' "$NORMALIZED" | grep -qE '^[[:space:]]*(echo|printf|git[[:space:]]+(commit|tag))([[:space:]]|$)'; then
29
+ exit 0
30
+ fi
31
+ fi
32
+
33
+ # Safe git force variants (--force-with-lease / --force-if-includes) are the
34
+ # recommended way to force-push without clobbering others' work. Strip them
35
+ # before matching so they do not trip the broad --force patterns; a bare
36
+ # --force or -f left behind still blocks.
37
+ SAFE_STRIPPED=$(printf '%s' "$NORMALIZED" | sed -E 's/--force-with-lease(=[^ ]*)?//g; s/--force-if-includes//g')
38
+
21
39
  # Destructive patterns — word-boundary aware where possible
22
40
  DESTRUCTIVE_PATTERNS=(
23
41
  # rm variants (short flags, long flags, separated flags, sudo, xargs/find piped)
@@ -69,7 +87,7 @@ DESTRUCTIVE_PATTERNS=(
69
87
  # Build combined regex
70
88
  REGEX=$(IFS='|'; echo "${DESTRUCTIVE_PATTERNS[*]}")
71
89
 
72
- if echo "$NORMALIZED" | grep -qEi "($REGEX)"; then
90
+ if echo "$SAFE_STRIPPED" | grep -qEi "($REGEX)"; then
73
91
  echo "WARNING: Potentially destructive command detected. Please verify." >&2
74
92
  exit 2
75
93
  fi
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ # loop-guard.sh — Advisory detection of repeated identical actions (stuck loops).
3
+ #
4
+ # Fires on: PostToolUse (Bash|Edit|MultiEdit|Write)
5
+ # Never blocks. Emits an advisory when the SAME tool action repeats at least
6
+ # THRESHOLD times within a short window — catching successful-but-identical
7
+ # loops that the /repeat circuit breaker (which only counts FAILURES) misses.
8
+ # Skipped in minimal profile; honours AI_TOOLKIT_DISABLED_HOOKS.
9
+ #
10
+ # Tunables: AI_TOOLKIT_LOOP_WINDOW (default 6), AI_TOOLKIT_LOOP_THRESHOLD (3).
11
+
12
+ # shellcheck source=_profile-check.sh
13
+ source "$(dirname "$0")/_profile-check.sh"
14
+ # shellcheck source=_hook-io.sh
15
+ source "$(dirname "$0")/_hook-io.sh"
16
+
17
+ INPUT=$(cat)
18
+ TOOL_NAME=$(hook_tool_name)
19
+ [ -z "$TOOL_NAME" ] && exit 0
20
+
21
+ # Build an identity for the action. For Bash it is the command; for edits it is
22
+ # file + new content, so normal iterative editing of one file does NOT trip the
23
+ # guard — only re-applying an IDENTICAL change does.
24
+ CMD=$(hook_command)
25
+ if [ -n "$CMD" ]; then
26
+ IDENT="$CMD"
27
+ else
28
+ FILE=$(hook_file_path)
29
+ [ -z "$FILE" ] && exit 0
30
+ IDENT="${FILE}::$(hook_new_content)"
31
+ fi
32
+
33
+ SID=$(hook_session_id)
34
+ STATE_DIR="${HOME}/.softspark/ai-toolkit/sessions"
35
+ mkdir -p "$STATE_DIR" 2>/dev/null || exit 0
36
+ LOG="${STATE_DIR}/${SID}-actions.log"
37
+
38
+ WINDOW="${AI_TOOLKIT_LOOP_WINDOW:-6}"
39
+ THRESHOLD="${AI_TOOLKIT_LOOP_THRESHOLD:-3}"
40
+
41
+ # Store only a short hash of "tool|identity" — never the raw payload.
42
+ HASH=$(printf '%s|%s' "$TOOL_NAME" "$IDENT" | { shasum -a 256 2>/dev/null || sha256sum 2>/dev/null; } | cut -c1-16)
43
+ [ -z "$HASH" ] && exit 0
44
+ printf '%s\n' "$HASH" >> "$LOG" 2>/dev/null || exit 0
45
+
46
+ # Keep only the last WINDOW entries so the file stays tiny.
47
+ lines=$(wc -l < "$LOG" 2>/dev/null | tr -d ' ')
48
+ if [ -n "$lines" ] && [ "$lines" -gt "$WINDOW" ]; then
49
+ tail -n "$WINDOW" "$LOG" > "${LOG}.tmp" 2>/dev/null && mv "${LOG}.tmp" "$LOG" 2>/dev/null
50
+ fi
51
+
52
+ COUNT=$(grep -cxF "$HASH" "$LOG" 2>/dev/null | tr -d ' ')
53
+ [ -z "$COUNT" ] && COUNT=0
54
+ if [ "$COUNT" -ge "$THRESHOLD" ]; then
55
+ AI_TOOLKIT_HOOK_FORMAT=json
56
+ hook_emit_context "PostToolUse" \
57
+ "Loop guard: the same ${TOOL_NAME} action has repeated ${COUNT}x within the last ${WINDOW} steps. If you are not making progress, stop and reassess — try a different approach or ask the user — instead of retrying the identical action."
58
+ fi
59
+ exit 0
@@ -58,9 +58,11 @@ if [ -f "$SESSION_FILE" ] && [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ] && [ "${AI
58
58
  printf '%s\n' "====================="
59
59
  fi
60
60
 
61
- # 3. Load active instincts (if any)
61
+ # 3. Load active instincts (if any). These are explicit, hand-authored files, so
62
+ # they load by default whenever present (unlike auto-saved session context above,
63
+ # which stays verbose-gated). No instincts on disk => no output, no token cost.
62
64
  INSTINCTS_DIR=".claude/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
65
+ if [ -d "$INSTINCTS_DIR" ] && [ "${AI_TOOLKIT_HOOK_QUIET:-0}" != "1" ] && ls "$INSTINCTS_DIR"/*.md >/dev/null 2>&1; then
64
66
  printf '%s\n' "=== Active Instincts ==="
65
67
  for f in "$INSTINCTS_DIR"/*.md; do
66
68
  printf '%s\n' "- $(head -1 "$f")"
package/app/hooks.json CHANGED
@@ -139,6 +139,16 @@
139
139
  }
140
140
  ]
141
141
  },
142
+ {
143
+ "_source": "ai-toolkit",
144
+ "matcher": "Bash|Edit|MultiEdit|Write",
145
+ "hooks": [
146
+ {
147
+ "type": "command",
148
+ "command": "\"$HOME/.softspark/ai-toolkit/hooks/loop-guard.sh\""
149
+ }
150
+ ]
151
+ },
142
152
  {
143
153
  "_source": "ai-toolkit",
144
154
  "matcher": "Edit|MultiEdit|Write",
@@ -5,13 +5,13 @@ Persistent session memory with SQLite storage and full-text search.
5
5
  ## Includes
6
6
  - Skills: `/mem-search` (FTS5 search across past sessions)
7
7
  - Hooks: `observation-capture.sh` (PostToolUse), `session-summary.sh` (Stop)
8
- - Scripts: `init_db.py` (database setup), `strip_private.py` (privacy filter)
8
+ - Scripts: `init_db.py` (database setup), `strip_private.py` (privacy filter + secret redaction)
9
9
 
10
10
  ## How It Works
11
11
  1. **Capture**: Every tool use is recorded to `~/.softspark/ai-toolkit/memory.db` (PostToolUse hook)
12
12
  2. **Summarize**: Session summary generated on each Stop hook (tools used, observation count, time range)
13
13
  3. **Search**: `/mem-search <query>` runs FTS5 full-text search with progressive disclosure
14
- 4. **Privacy**: Content between `<private>...</private>` tags is stripped before storage
14
+ 4. **Privacy**: `strip_private.py` runs before storage — it removes `<private>...</private>` blocks and redacts high-confidence secrets (API keys, tokens, private keys) to `[REDACTED:<label>]`
15
15
 
16
16
  ## Database Schema
17
17
  - `sessions` — one row per Claude Code session (id, project_dir, started_at, ended_at, summary)
@@ -1,20 +1,47 @@
1
1
  #!/usr/bin/env python3
2
- """Remove <private>...</private> blocks from stdin.
2
+ """Sanitize stdin before it is stored in the session memory database.
3
3
 
4
- Used by observation-capture.sh to sanitize content before storage.
5
- Handles multi-line private blocks and nested angle brackets.
4
+ Two passes:
5
+ 1. Remove ``<private>...</private>`` blocks (explicit user opt-out).
6
+ 2. Redact high-confidence secrets (API keys, tokens, private keys) so a token
7
+ that scrolls through a tool output never lands in the SQLite memory store.
6
8
 
7
- Usage: echo "text <private>secret</private> more" | python3 strip_private.py
9
+ Used by observation-capture.sh and session-summary.sh.
10
+
11
+ Usage: echo "text <private>secret</private> sk-..." | python3 strip_private.py
8
12
  """
9
13
  from __future__ import annotations
10
14
 
11
15
  import re
12
16
  import sys
13
17
 
18
+ # High-confidence, structural secret patterns only. These match a specific
19
+ # token shape (not "password = ..." prose) so false positives stay near zero —
20
+ # important because over-redaction silently corrupts stored observations.
21
+ _SECRET_PATTERNS: list[tuple[re.Pattern[str], str]] = [
22
+ (re.compile(r"AKIA[0-9A-Z]{16}"), "aws-key"),
23
+ (re.compile(r"\bsk-[A-Za-z0-9]{20,}"), "api-key"),
24
+ (re.compile(r"\bgh[posru]_[A-Za-z0-9]{36,}"), "github-token"),
25
+ (re.compile(r"\bxox[baprs]-[A-Za-z0-9-]{10,}"), "slack-token"),
26
+ (re.compile(r"\bAIza[0-9A-Za-z_\-]{35}"), "google-key"),
27
+ (re.compile(
28
+ r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----"
29
+ r"[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----"
30
+ ), "private-key"),
31
+ ]
32
+
33
+
34
+ def scrub_secrets(text: str) -> str:
35
+ """Replace recognised secret tokens with a labelled redaction marker."""
36
+ for pattern, label in _SECRET_PATTERNS:
37
+ text = pattern.sub(f"[REDACTED:{label}]", text)
38
+ return text
39
+
14
40
 
15
41
  def main() -> None:
16
42
  content = sys.stdin.read()
17
43
  cleaned = re.sub(r"<private>.*?</private>", "", content, flags=re.DOTALL)
44
+ cleaned = scrub_secrets(cleaned)
18
45
  sys.stdout.write(cleaned)
19
46
 
20
47
 
@@ -23,6 +23,7 @@ Create a new Claude Code hook following ai-toolkit conventions.
23
23
  | `SessionEnd` | Session is closing | any | Flush logs, save transcripts |
24
24
  | `UserPromptSubmit` | User submits a prompt | any | Prompt governance, usage tracking |
25
25
  | `Notification` | Claude sends a notification | any | OS alerts, Slack pings |
26
+ | `MessageDisplay` | Assistant message is about to be shown to the user | any | Transform or hide assistant message text before display |
26
27
 
27
28
  ### Tool lifecycle
28
29
 
@@ -13,9 +13,9 @@ $ARGUMENTS
13
13
 
14
14
  ## What This Does
15
15
 
16
- Manages the instinct system that learns patterns from your sessions.
16
+ Manages the instinct system: project-local behavioral notes that Claude loads at the start of a session.
17
17
 
18
- Instincts are stored in `.claude/instincts/` and loaded at session start.
18
+ Instincts are markdown files in `.claude/instincts/`, loaded at session start by `session-start.sh` whenever any exist (set `AI_TOOLKIT_HOOK_QUIET=1` to suppress).
19
19
 
20
20
  ## Commands
21
21
 
@@ -48,10 +48,10 @@ Interactive review: shows each instinct and asks promote/remove/keep.
48
48
 
49
49
  ## How Instincts Work
50
50
 
51
- 1. **Extraction**: At session end, the Stop hook extracts patterns from the session
52
- 2. **Storage**: Saved as `.claude/instincts/<pattern-name>.md` with confidence score
53
- 3. **Loading**: At session start, instincts are loaded and shown to Claude
54
- 4. **Curation**: Use `/instinct-review` to promote good ones and remove bad ones
51
+ 1. **Authoring**: Instinct files are written by hand one markdown file per pattern in `.claude/instincts/`. There is no automatic session-end extractor today (see [When NOT to Use](#when-not-to-use)).
52
+ 2. **Storage**: `.claude/instincts/<pattern-name>.md`, each carrying a confidence score (see format below).
53
+ 3. **Loading**: At session start, `session-start.sh` loads every instinct file into context whenever any exist. No instincts on disk means nothing is loaded; set `AI_TOOLKIT_HOOK_QUIET=1` to suppress.
54
+ 4. **Curation**: Use `/instinct-review` to list, promote, remove, or clear them.
55
55
 
56
56
  ## Instinct Format
57
57
 
@@ -88,14 +88,14 @@ Last seen: 2026-03-25
88
88
  ## Gotchas
89
89
 
90
90
  - Instincts live in **project-local** `.claude/instincts/`, not in `~/.softspark/ai-toolkit/`. Running this skill in a different project sees a different set — do not treat the list as global state.
91
- - The Stop hook that extracts instincts may write draft files even when no meaningful pattern was observed. A `.claude/instincts/` with 40 files is usually 35 noise + 5 signal curate ruthlessly.
91
+ - Every instinct file loads into session context by default (whenever the directory is non-empty), so each one costs startup tokens. This is why curation matters prune aggressively and keep the set small.
92
92
  - Promoted instincts (confidence = 1.0) load into every session's context, costing tokens. Too many pinned instincts bloat startup. Keep ≤10 pinned.
93
- - Instinct files are plain markdown but the extraction format may evolve between ai-toolkit versions. A `--clear` after a version bump is often cleaner than trying to migrate old formats.
93
+ - Instinct files are plain markdown following the format above. If you accumulate many, a `--clear` and re-author is often cleaner than migrating stale notes after a major toolkit bump.
94
94
  - The filename (`<pattern-name>.md`) is the identity used by `--promote` and `--remove`. Renaming files manually breaks those flags until the user reopens the review UI.
95
95
 
96
96
  ## When NOT to Use
97
97
 
98
- - To **extract** new instincts — extraction is automatic via the Stop hook
98
+ - To **auto-extract** instincts from a session not implemented. No Stop hook writes instinct files; author them by hand (or via a future extraction tool). This skill curates existing files, it does not generate them.
99
99
  - To search past session memory — use `/mem-search`
100
100
  - To edit global toolkit memory files — those live in `~/.claude/projects/*/memory/` and are managed by the auto-memory system, not this skill
101
- - To permanently disable the instinct system edit `settings.json` to remove the Stop hook; `--clear` only wipes current state, extraction continues on the next session
101
+ - To stop instincts from loading — delete the files with `--clear`, or set `AI_TOOLKIT_HOOK_QUIET=1` to suppress all session-start output. There is no extraction process to disable.
@@ -73,6 +73,16 @@ Scan skill and agent definitions for security risks before installation or after
73
73
  | `-----BEGIN.*PRIVATE KEY` | HIGH | Private key |
74
74
  | `ghp_[a-zA-Z0-9]{36}` | HIGH | GitHub PAT |
75
75
 
76
+ ### Unicode Safety
77
+
78
+ Shipped prompt text (skills, agents, rules, personas, mcp-templates) is scanned for invisible/smuggled characters that a human reviewer cannot see. `U+200D` (ZWJ) is allowlisted so legitimate emoji sequences do not flag.
79
+
80
+ | Pattern | Severity | Description |
81
+ |---------|----------|-------------|
82
+ | Tag block `U+E0000–U+E007F` | HIGH | ASCII smuggling / invisible prompt injection |
83
+ | Bidi controls (LRE/RLE/PDF/LRO/RLO, LRI/RLI/FSI/PDI) | HIGH | Trojan Source text reordering |
84
+ | Zero-width / invisible format chars (ZWSP, ZWNJ, WJ, BOM, soft hyphen, …) | WARN | Verify it is intentional |
85
+
76
86
  ## Output Format
77
87
 
78
88
  ```markdown
@@ -105,6 +105,25 @@ CORRECT: Agent reports success → Check VCS diff → Verify changes → Report
105
105
  WRONG: Trust agent report at face value
106
106
  ```
107
107
 
108
+ ## Live-App Rubric Verification (optional)
109
+
110
+ When the success criterion is **behavioral or visual** (a UI flow, a generated app, a multi-step interaction), a pass/fail command is not enough — the proof is the running app, observed. Use a weighted rubric instead of a single assertion:
111
+
112
+ 1. **Define the rubric BEFORE building** — 3–6 criteria, each with a weight and an explicit pass bar. Example:
113
+
114
+ | Criterion | Weight | Pass bar |
115
+ |-----------|--------|----------|
116
+ | Core flow completes end-to-end | 0.40 | No error, reaches success state |
117
+ | Empty / loading / error states render | 0.25 | All three visible |
118
+ | Matches the requested layout | 0.20 | No major deviation |
119
+ | No console errors | 0.15 | Console clean |
120
+
121
+ 2. **Launch the app and observe** — actually run it and capture the behavior (screenshot, console, network). Do not infer from the source.
122
+ 3. **Score with a fresh evaluator** — have an independent agent grade the observed behavior against the rubric, not the implementer who wrote it (self-grading anchors high). Compute the weighted score.
123
+ 4. **Gate on the threshold** — below the bar (e.g. < 0.8) the claim is NOT verified: list the failing criteria as concrete defects and iterate. At or above the bar, state the score WITH the captured evidence.
124
+
125
+ The rubric is the verification command for work that has no green/red exit code. The same Iron Law applies: observed evidence before the claim, every time.
126
+
108
127
  ## Constitutional Anchors
109
128
 
110
129
  This skill enforces **Constitution Art. VI.4 (Verify Before Claiming Done)**. The diff re-read is not optional: before any completion claim, confirm no orphaned references, no missing test coverage for changed paths, no stale docs. A task is not done while any of those exist.