@softspark/ai-toolkit 4.19.0 → 4.20.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.
Files changed (216) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/LICENSE +201 -21
  3. package/NOTICE +55 -0
  4. package/README.md +23 -13
  5. package/app/.claude-plugin/plugin.json +2 -2
  6. package/app/hooks/_hook-io.sh +4 -0
  7. package/app/hooks/_locate-toolkit.sh +4 -0
  8. package/app/hooks/_profile-check.sh +4 -0
  9. package/app/hooks/_search-capability.sh +4 -0
  10. package/app/hooks/_session-paths.sh +4 -0
  11. package/app/hooks/ai-toolkit-statusline.sh +4 -0
  12. package/app/hooks/commit-quality.sh +4 -0
  13. package/app/hooks/config-desync-guard.sh +4 -0
  14. package/app/hooks/governance-capture.sh +4 -0
  15. package/app/hooks/guard-config.sh +4 -0
  16. package/app/hooks/guard-destructive.sh +4 -0
  17. package/app/hooks/guard-path.sh +4 -0
  18. package/app/hooks/instructions-audit.sh +4 -0
  19. package/app/hooks/loop-guard.sh +4 -0
  20. package/app/hooks/mcp-health.sh +4 -0
  21. package/app/hooks/notify-waiting.sh +4 -0
  22. package/app/hooks/post-tool-use.sh +4 -0
  23. package/app/hooks/pre-compact-save.sh +4 -0
  24. package/app/hooks/pre-compact.sh +4 -0
  25. package/app/hooks/quality-check.sh +4 -0
  26. package/app/hooks/quality-gate.sh +4 -0
  27. package/app/hooks/revert-guard.sh +4 -0
  28. package/app/hooks/save-session.sh +4 -0
  29. package/app/hooks/search-tracker.sh +4 -0
  30. package/app/hooks/session-end.sh +4 -0
  31. package/app/hooks/session-start.sh +4 -0
  32. package/app/hooks/stop-search-check.sh +4 -0
  33. package/app/hooks/subagent-start.sh +4 -0
  34. package/app/hooks/subagent-stop.sh +4 -0
  35. package/app/hooks/test-cohesion.sh +4 -0
  36. package/app/hooks/track-usage.sh +4 -0
  37. package/app/hooks/user-prompt-submit.sh +4 -0
  38. package/app/plugins/README.md +15 -15
  39. package/app/plugins/enterprise-pack/hooks/output-style.sh +4 -0
  40. package/app/plugins/enterprise-pack/hooks/status-line.sh +4 -0
  41. package/app/plugins/memory-pack/hooks/observation-capture.sh +4 -0
  42. package/app/plugins/memory-pack/hooks/session-summary.sh +4 -0
  43. package/app/plugins/memory-pack/scripts/init_db.py +4 -0
  44. package/app/plugins/memory-pack/scripts/strip_private.py +4 -0
  45. package/app/skills/_lib/__init__.py +4 -0
  46. package/app/skills/_lib/detect_utils.py +4 -0
  47. package/app/skills/a11y-validate/scripts/a11y-scanner.py +4 -0
  48. package/app/skills/analyze/scripts/complexity.py +4 -0
  49. package/app/skills/brand-voice/scripts/measure.py +4 -0
  50. package/app/skills/build/scripts/detect-build.py +4 -0
  51. package/app/skills/ci/scripts/ci-detect.py +4 -0
  52. package/app/skills/commit/scripts/pre-commit-check.py +4 -0
  53. package/app/skills/cve-scan/scripts/cve_scan.py +4 -0
  54. package/app/skills/debug/scripts/error-parser.py +4 -0
  55. package/app/skills/deploy/scripts/pre_deploy_check.py +4 -0
  56. package/app/skills/docs/scripts/doc-inventory.py +4 -0
  57. package/app/skills/explain/scripts/dependency-graph.py +4 -0
  58. package/app/skills/explore/scripts/visualize.py +4 -0
  59. package/app/skills/fix/scripts/error-classifier.py +4 -0
  60. package/app/skills/health/scripts/health_check.py +4 -0
  61. package/app/skills/hipaa-validate/scripts/hipaa_scan.py +4 -0
  62. package/app/skills/lint/scripts/detect-linters.py +4 -0
  63. package/app/skills/migrate/scripts/migration-status.py +4 -0
  64. package/app/skills/plugin-creator/SKILL.md +18 -8
  65. package/app/skills/pr/scripts/pr-summary.py +4 -0
  66. package/app/skills/refactor/scripts/refactor-scan.py +4 -0
  67. package/app/skills/review/scripts/diff-analyzer.py +4 -0
  68. package/app/skills/rollback/scripts/rollback_info.py +4 -0
  69. package/app/skills/seo-validate/scripts/seo-scanner.py +4 -0
  70. package/app/skills/skill-creator/templates/reasoning-engine/search.py +4 -0
  71. package/app/skills/test/scripts/detect-runner.py +4 -0
  72. package/app/skills/write-a-prd/scripts/poll.js +4 -0
  73. package/benchmarks/ecosystem-doctor-snapshot.json +3 -3
  74. package/benchmarks/run.py +4 -0
  75. package/bin/ai-toolkit.js +4 -0
  76. package/kb/{planning/drop-cascade-hooks-after-sunset.md → history/completed/drop-cascade-hooks-after-sunset-20260710.md} +24 -0
  77. package/kb/{reference/language-packs.md → history/completed/language-packs-removed-20260727.md} +32 -7
  78. package/kb/{planning/mcp-context-trim-v4-prd.md → history/completed/mcp-context-trim-v4-prd-obsoleted-20260727.md} +43 -9
  79. package/kb/history/completed/no-op-plugin-packs-removed-20260727.md +127 -0
  80. package/kb/history/completed/tool-output-token-reduction-closed-20260727.md +190 -0
  81. package/kb/procedures/release-preparation-sop.md +83 -5
  82. package/kb/reference/comparison.md +1 -1
  83. package/kb/reference/enterprise-config-guide.md +1 -1
  84. package/kb/reference/licensing.md +148 -0
  85. package/kb/reference/plugin-pack-conventions.md +24 -16
  86. package/llms-full.txt +1181 -529
  87. package/llms.txt +6 -3
  88. package/manifest.json +1 -1
  89. package/package.json +3 -2
  90. package/scripts/_common.py +4 -0
  91. package/scripts/add_rule.py +4 -0
  92. package/scripts/audit_skills.py +4 -0
  93. package/scripts/benchmark_config.py +4 -0
  94. package/scripts/benchmark_ecosystem.py +4 -0
  95. package/scripts/check_deps.py +4 -0
  96. package/scripts/claude_app.py +4 -0
  97. package/scripts/codex_skill_adapter.py +4 -0
  98. package/scripts/compile_slm.py +4 -0
  99. package/scripts/config_cli.py +4 -0
  100. package/scripts/config_lock.py +4 -0
  101. package/scripts/config_merger.py +4 -0
  102. package/scripts/config_resolver.py +4 -0
  103. package/scripts/config_scaffold.py +5 -1
  104. package/scripts/config_validator.py +4 -0
  105. package/scripts/create_skill.py +4 -0
  106. package/scripts/dir_rules_shared.py +4 -0
  107. package/scripts/doctor.py +4 -0
  108. package/scripts/ecosystem_doctor.py +4 -0
  109. package/scripts/eject.py +4 -0
  110. package/scripts/emission.py +4 -0
  111. package/scripts/evaluate_skills.py +4 -0
  112. package/scripts/frontmatter.py +4 -0
  113. package/scripts/generate_agents_md.py +4 -0
  114. package/scripts/generate_aider_conf.py +4 -0
  115. package/scripts/generate_antigravity.py +4 -0
  116. package/scripts/generate_augment.py +4 -0
  117. package/scripts/generate_augment_agents.py +4 -0
  118. package/scripts/generate_augment_commands.py +4 -0
  119. package/scripts/generate_augment_hooks.py +4 -0
  120. package/scripts/generate_augment_rules.py +4 -0
  121. package/scripts/generate_augment_skills.py +4 -0
  122. package/scripts/generate_cline.py +4 -0
  123. package/scripts/generate_cline_rules.py +4 -0
  124. package/scripts/generate_cline_skills.py +4 -0
  125. package/scripts/generate_codex.py +4 -0
  126. package/scripts/generate_codex_agents.py +4 -0
  127. package/scripts/generate_codex_hooks.py +4 -0
  128. package/scripts/generate_codex_skills.py +4 -0
  129. package/scripts/generate_conventions.py +4 -0
  130. package/scripts/generate_copilot.py +4 -0
  131. package/scripts/generate_copilot_hooks.py +4 -0
  132. package/scripts/generate_cursor_agents.py +4 -0
  133. package/scripts/generate_cursor_hooks.py +4 -0
  134. package/scripts/generate_cursor_mdc.py +4 -0
  135. package/scripts/generate_cursor_rules.py +4 -0
  136. package/scripts/generate_cursor_skills.py +4 -0
  137. package/scripts/generate_devin_hooks.py +4 -0
  138. package/scripts/generate_gemini.py +4 -0
  139. package/scripts/generate_gemini_commands.py +4 -0
  140. package/scripts/generate_gemini_hooks.py +4 -0
  141. package/scripts/generate_gemini_skills.py +4 -0
  142. package/scripts/generate_language_rules_skills.py +4 -0
  143. package/scripts/generate_llms_txt.py +4 -0
  144. package/scripts/generate_opencode.py +4 -0
  145. package/scripts/generate_opencode_agents.py +4 -0
  146. package/scripts/generate_opencode_commands.py +4 -0
  147. package/scripts/generate_opencode_json.py +4 -0
  148. package/scripts/generate_opencode_plugin.py +4 -0
  149. package/scripts/generate_roo_modes.py +4 -0
  150. package/scripts/generate_roo_rules.py +4 -0
  151. package/scripts/generate_windsurf.py +4 -0
  152. package/scripts/generate_windsurf_rules.py +4 -0
  153. package/scripts/generate_windsurf_skills.py +4 -0
  154. package/scripts/generator_base.py +4 -0
  155. package/scripts/harvest_ecosystem.py +4 -0
  156. package/scripts/hook_sources.py +4 -0
  157. package/scripts/inject_hook_cli.py +4 -0
  158. package/scripts/inject_mcp_cli.py +4 -0
  159. package/scripts/inject_rule_cli.py +4 -0
  160. package/scripts/inject_section_cli.py +4 -0
  161. package/scripts/injection.py +4 -0
  162. package/scripts/install.py +4 -0
  163. package/scripts/install_git_hooks.py +4 -0
  164. package/scripts/install_steps/__init__.py +4 -0
  165. package/scripts/install_steps/ai_tools.py +4 -0
  166. package/scripts/install_steps/detect_language.py +4 -0
  167. package/scripts/install_steps/hooks.py +4 -0
  168. package/scripts/install_steps/install_state.py +4 -0
  169. package/scripts/install_steps/markers.py +4 -0
  170. package/scripts/install_steps/project_registry.py +4 -0
  171. package/scripts/install_steps/symlinks.py +4 -0
  172. package/scripts/instruction_core.py +4 -0
  173. package/scripts/mcp_editors.py +4 -0
  174. package/scripts/mcp_manager.py +4 -0
  175. package/scripts/mcp_sources.py +4 -0
  176. package/scripts/merge-hooks.py +4 -0
  177. package/scripts/migrate.py +4 -0
  178. package/scripts/output_filter_retirement.py +4 -0
  179. package/scripts/pack_codebase.py +4 -0
  180. package/scripts/paths.py +4 -0
  181. package/scripts/plugin.py +4 -0
  182. package/scripts/plugin_schema.py +4 -0
  183. package/scripts/projects_cli.py +4 -0
  184. package/scripts/propagate_global.py +4 -0
  185. package/scripts/remove_rule.py +4 -0
  186. package/scripts/rule_sources.py +4 -0
  187. package/scripts/secure_fs.py +4 -0
  188. package/scripts/session_state.py +4 -0
  189. package/scripts/session_token_stats.py +4 -0
  190. package/scripts/skill_pointer.py +4 -0
  191. package/scripts/stats.py +4 -0
  192. package/scripts/sync.py +4 -0
  193. package/scripts/test_cohesion.py +4 -0
  194. package/scripts/uninstall.py +4 -0
  195. package/scripts/update_projects.py +4 -0
  196. package/scripts/url_fetch.py +4 -0
  197. package/scripts/validate.py +4 -0
  198. package/scripts/version_check.py +4 -0
  199. package/app/plugins/csharp-pack/README.md +0 -11
  200. package/app/plugins/csharp-pack/plugin.json +0 -18
  201. package/app/plugins/frontend-pack/README.md +0 -14
  202. package/app/plugins/frontend-pack/plugin.json +0 -22
  203. package/app/plugins/java-pack/README.md +0 -11
  204. package/app/plugins/java-pack/plugin.json +0 -18
  205. package/app/plugins/kotlin-pack/README.md +0 -11
  206. package/app/plugins/kotlin-pack/plugin.json +0 -18
  207. package/app/plugins/research-pack/README.md +0 -14
  208. package/app/plugins/research-pack/plugin.json +0 -22
  209. package/app/plugins/ruby-pack/README.md +0 -11
  210. package/app/plugins/ruby-pack/plugin.json +0 -18
  211. package/app/plugins/rust-pack/README.md +0 -11
  212. package/app/plugins/rust-pack/plugin.json +0 -18
  213. package/app/plugins/security-pack/README.md +0 -15
  214. package/app/plugins/security-pack/plugin.json +0 -23
  215. package/app/plugins/swift-pack/README.md +0 -11
  216. package/app/plugins/swift-pack/plugin.json +0 -18
package/llms-full.txt CHANGED
@@ -14,19 +14,22 @@
14
14
  - [Best Practices](kb/best-practices/README.md)
15
15
  - [No Hardcoded Counts in Secondary Docs](kb/best-practices/no-hardcoded-counts.md)
16
16
  - [Plan: Deep Coverage v3.0 — 100% Native Surface Utilization](kb/history/completed/deep-coverage-v3-20260423.md)
17
+ - [Plan: Drop Cascade hooks after 2026-07-01 sunset](kb/history/completed/drop-cascade-hooks-after-sunset-20260710.md)
17
18
  - [Plan: Ecosystem Deep Sweep — All 12 Supported Tools](kb/history/completed/ecosystem-deep-sweep-20260423.md)
18
19
  - [Plan: Enterprise Config Inheritance — Multi-Repo Governance with `extends`](kb/history/completed/enterprise-config-inheritance-plan-20260412.md)
19
20
  - [Spike: F2 MCP Context Trim — Hook Feasibility & Path Decision](kb/history/completed/f2-mcp-trim-spike-20260504.md)
21
+ - [Language Plugin Packs — REMOVED](kb/history/completed/language-packs-removed-20260727.md)
22
+ - [PRD: MCP Context Trim v4.0 — ABANDONED](kb/history/completed/mcp-context-trim-v4-prd-obsoleted-20260727.md)
20
23
  - [Implementation Plan: Native Tool Output Filter](kb/history/completed/native-tool-output-filter-plan.md)
24
+ - [Removed: Nine Plugin Packs That Installed Nothing](kb/history/completed/no-op-plugin-packs-removed-20260727.md)
21
25
  - [Plan: Offline-First SLM Profile — Lightweight Mode for Local Models](kb/history/completed/offline-slm-profile-plan-20260411.md)
22
26
  - [Retirement: Native Tool-Output Filter](kb/history/completed/output-filter-retirement-20260726.md)
23
27
  - [Plan: Output & Token Discipline](kb/history/completed/output-token-discipline-plan-20260504.md)
24
28
  - [rtk Pack Integration](kb/history/completed/rtk-pack-integration-20260726.md)
25
29
  - [Retirement: rtk-pack](kb/history/completed/rtk-pack-retirement-20260727.md)
30
+ - [Closed: Tool-Output Token Reduction](kb/history/completed/tool-output-token-reduction-closed-20260727.md)
26
31
  - [How-To Guides](kb/howto/README.md)
27
32
  - [Plan: Cloud Security Pack — Multi-Cloud Audit](kb/planning/cloud-security-pack-plan.md)
28
- - [Plan: Drop Cascade hooks after 2026-07-01 sunset](kb/planning/drop-cascade-hooks-after-sunset.md)
29
- - [PRD: MCP Context Trim v4.0](kb/planning/mcp-context-trim-v4-prd.md)
30
33
  - [SOP: Ecosystem Sync](kb/procedures/ecosystem-sync-sop.md)
31
34
  - [SOP: AI Toolkit Maintenance](kb/procedures/maintenance-sop.md)
32
35
  - [SOP: Post-Release Testing](kb/procedures/post-release-testing-sop.md)
@@ -51,8 +54,8 @@
51
54
  - [Hierarchical Override Pattern](kb/reference/hierarchical-override-pattern.md)
52
55
  - [Hooks Catalog](kb/reference/hooks-catalog.md)
53
56
  - [External Integrations](kb/reference/integrations.md)
54
- - [Language Plugin Packs](kb/reference/language-packs.md)
55
57
  - [Language Rules System](kb/reference/language-rules.md)
58
+ - [Licensing](kb/reference/licensing.md)
56
59
  - [Manifest-Driven Install System](kb/reference/manifest-install.md)
57
60
  - [MCP Editor Compatibility](kb/reference/mcp-editor-compatibility.md)
58
61
  - [MCP Server Templates](kb/reference/mcp-templates.md)
@@ -458,6 +461,131 @@ Definition of "100% coverage" chosen: **each editor works at 100% of its native
458
461
 
459
462
  ---
460
463
 
464
+ ## kb/history/completed/drop-cascade-hooks-after-sunset-20260710.md
465
+
466
+ ---
467
+ title: "Plan: Drop Cascade hooks after 2026-07-01 sunset"
468
+ category: planning
469
+ service: ai-toolkit
470
+ tags:
471
+ - windsurf
472
+ - devin
473
+ - cascade
474
+ - hooks
475
+ - deprecation
476
+ - cleanup
477
+ doc_type: plan
478
+ status: completed
479
+ created: "2026-06-10"
480
+ last_updated: "2026-07-10"
481
+ completion: "100%"
482
+ trigger_date: "2026-07-01"
483
+ description: "Completed cleanup of the deprecated Windsurf Cascade hooks generator after the 2026-07-01 sunset; Devin CLI .devin/hooks.v1.json is now the sole live hook surface."
484
+ ---
485
+
486
+ # Plan: Drop Cascade hooks after 2026-07-01 sunset
487
+
488
+ **Completed in v4.13.0 (2026-07-10).** The deprecated generator and install/test wiring were removed; the Devin hook generator remains.
489
+
490
+ > **Filed to history 2026-07-27.** The plan was finished in v4.13.0 but sat in
491
+ > `kb/planning/` for another two and a half weeks, where it read as open work.
492
+ > Before moving it, every claim in the Verification section below was re-run
493
+ > against the codebase:
494
+ >
495
+ > | Check | Result |
496
+ > |---|---|
497
+ > | `scripts/generate_windsurf_hooks.py` deleted | gone |
498
+ > | `grep -rn generate_windsurf_hooks scripts/ tests/` | no source references (one stale `.pyc` under gitignored `__pycache__`) |
499
+ > | `_HOOK_STEM_ALIAS = {"devin": "windsurf"}` retained in `validate.py` | present, line 882 |
500
+ > | windsurf `our_generators` in `scripts/ecosystem_tools.json` | Cascade generator absent, `generate_devin_hooks.py` present |
501
+ > | `kb/reference/supported-tools-registry.md` hooks-migration row | reads "Complete" in past tense |
502
+ > | `validate.py --strict` | 0 errors, 0 warnings |
503
+ >
504
+ > The work was real and complete. Only the filing was wrong.
505
+ >
506
+ > **Process note.** This is the second document found misfiled in
507
+ > `kb/planning/` on the same day; the other,
508
+ > [`mcp-context-trim-v4-prd-obsoleted-20260727.md`](mcp-context-trim-v4-prd-obsoleted-20260727.md),
509
+ > had gone obsolete because the platform shipped the fix first. A plan with a
510
+ > `trigger_date` needs a matching move-to-history step in the release that acts
511
+ > on it — otherwise `kb/planning/` accumulates work that is already done or no
512
+ > longer worth doing, and the next reader cannot tell which is which.
513
+
514
+ ## Why this exists
515
+
516
+ Windsurf rebranded to Devin Desktop on 2026-06-02. The Cascade agent — and its
517
+ `.windsurf/hooks.json` hook surface (`agent_action_name`/`tool_info` format) — is
518
+ available **only through 2026-07-01**. Devin Local / Devin CLI do **not** read
519
+ `.windsurf/hooks.json` as a fallback.
520
+
521
+ v4.8.0 already shipped the replacement: `generate_devin_hooks.py` emits
522
+ `.devin/hooks.v1.json` in the Claude-compatible format Devin CLI uses. During the
523
+ transition **both** generators run at `profile=full` so pre-sunset Cascade users
524
+ keep working. After 2026-07-01 the Cascade half is dead code and must be removed
525
+ (Constitution Art. VI.1 — no dead code).
526
+
527
+ ## Trigger
528
+
529
+ First ai-toolkit release **on or after 2026-07-01**. Do NOT do this earlier —
530
+ removing it before the sunset breaks Cascade users who are still on the old agent.
531
+
532
+ ## Scope — remove the Cascade hooks surface
533
+
534
+ 1. **Delete the generator:** `scripts/generate_windsurf_hooks.py`.
535
+ 2. **Unwire the install step:** in `scripts/install_steps/ai_tools.py`, remove the
536
+ `_try_generator("generate_windsurf_hooks", cwd)` call (keep
537
+ `generate_devin_hooks`). Update the `profile=full` dry-run message to drop
538
+ `.windsurf/hooks.json (Cascade, deprecated)`.
539
+ 3. **Tests:** remove the windsurf-`.windsurf/hooks.json` cases from
540
+ `tests/test_hooks_per_editor.bats` (output path, valid JSON, source tag,
541
+ `$HOME` prefix, idempotence, user-preservation, `pre_write_code` coverage) and
542
+ the `profile=full` assertion in `tests/test_install_profiles.bats`
543
+ (`windsurf + full emits .windsurf/hooks.json`). Keep all `.devin/hooks.v1.json`
544
+ tests. Adjust the README test-count badge to the new total.
545
+ 4. **Registry:** in `scripts/ecosystem_tools.json` (windsurf entry), remove
546
+ `scripts/generate_windsurf_hooks.py` from `our_generators`; keep
547
+ `.windsurf/hooks.json` out of `config_paths` (it was never listed). Trim the
548
+ `status_note` hooks-migration paragraph to past tense ("Cascade hooks removed
549
+ in vX.Y.Z").
550
+ 5. **Docs:** in `kb/reference/supported-tools-registry.md` drop the
551
+ `generate_windsurf_hooks.py` row and the "drop after 2026-07-01" note; in
552
+ `kb/reference/hooks-catalog.md` remove the Cascade row from the
553
+ Per-Editor Native Hooks table and the deprecation wording, leaving the Devin CLI
554
+ section as the windsurf-family hook surface.
555
+ 6. **validate.py:** the `_HOOK_STEM_ALIAS = {"devin": "windsurf"}` mapping STAYS —
556
+ it is what keeps the `devin` hook generator counted as windsurf hooks in the
557
+ README-honesty check after the Cascade generator is gone.
558
+ 7. **CHANGELOG / version:** minor bump, `Removed` entry, regen artifacts, full
559
+ release-preparation SOP gate.
560
+
561
+ ## Verification
562
+
563
+ - `python3 scripts/validate.py --strict` — 0/0 (editor-hooks-honesty must still
564
+ report windsurf as hook-enabled via the `devin` generator alias).
565
+ - `python3 scripts/ecosystem_doctor.py --offline --check` — exit 0.
566
+ - `npm test` — 0 `not ok`; no test recreates the deleted
567
+ `generate_windsurf_hooks.py` generator.
568
+ - `grep -rn "generate_windsurf_hooks" scripts/ tests/` returns nothing
569
+ (Art. VI.1 orphan check — the deleted generator is fully unwired).
570
+ `.windsurf/hooks.json` intentionally remains referenced by the one-time
571
+ migration/strip cleanup (`scripts/install_steps/ai_tools.py`) and its test,
572
+ and in narrative docs (CHANGELOG, README, `kb/`, docstrings).
573
+
574
+ ## Do NOT touch
575
+
576
+ - `generate_devin_hooks.py` and `.devin/hooks.v1.json` — the live replacement.
577
+ - The `.devin/`/`.windsurf/` rules + skills dual-emit (that fallback persists as
578
+ long as Devin Desktop reads legacy `.windsurf/` paths; this plan is hooks-only).
579
+
580
+ ## Related
581
+
582
+ - `kb/reference/hooks-catalog.md` — Per-Editor Native Hooks + Devin CLI section
583
+ - `kb/reference/supported-tools-registry.md` — windsurf entry, hooks-migration row
584
+ - `kb/procedures/ecosystem-sync-sop.md` — class-D deprecation workflow
585
+ - `scripts/ecosystem_tools.json` — windsurf `status_note`
586
+
587
+ ---
588
+
461
589
  ## kb/history/completed/ecosystem-deep-sweep-20260423.md
462
590
 
463
591
  ---
@@ -1780,110 +1908,389 @@ Estimate in the PRD: ~8 working days.
1780
1908
 
1781
1909
  ---
1782
1910
 
1783
- ## kb/history/completed/native-tool-output-filter-plan.md
1911
+ ## kb/history/completed/language-packs-removed-20260727.md
1784
1912
 
1785
1913
  ---
1786
- title: "Implementation Plan: Native Tool Output Filter"
1914
+ title: "AI Toolkit - Language Plugin Packs (removed)"
1787
1915
  category: planning
1788
1916
  service: ai-toolkit
1789
- tags:
1790
- - output-filter
1791
- - hooks
1792
- - recovery
1793
- - performance
1794
- - claude-code
1795
- doc_type: plan
1917
+ tags: [plugins, languages, rust, java, csharp, kotlin, swift, ruby, removed]
1918
+ doc_type: postmortem
1796
1919
  status: completed
1797
- created: "2026-07-23"
1798
- last_updated: "2026-07-23"
1799
- completed: "2026-07-23"
1800
- completion: "100% of approved Claude Code scope; other runtimes remain manual-only by capability decision"
1801
- shipped_in: "Unreleased"
1802
- description: "Approved implementation plan and completion evidence for the original dependency-free ai-toolkit tool-output filter, including conservative profiles, exact recovery, telemetry, runtime capability gates, and adjacent repairs."
1920
+ version: "1.1.0"
1921
+ created: "2026-03-29"
1922
+ last_updated: "2026-07-27"
1923
+ description: "REMOVED 2026-07-27 in v4.20.0. The six language packs wrapped skills that already ship in core, so installing one put zero files on disk. The skills themselves (rust-patterns, java-patterns, csharp-patterns, kotlin-patterns, swift-patterns, ruby-patterns) were never in the packs and are unaffected."
1924
+ ---
1925
+
1926
+ # Language Plugin Packs — REMOVED
1927
+
1928
+ > **Removed 2026-07-27 in v4.20.0. Nothing was lost.**
1929
+ >
1930
+ > The six packs described below each declared exactly one skill —
1931
+ > `rust-patterns`, `java-patterns`, `csharp-patterns`, `kotlin-patterns`,
1932
+ > `swift-patterns`, `ruby-patterns` — and every one of those skills lives in
1933
+ > `app/skills/`, is part of the core install, and **still does**. The packs
1934
+ > owned no files of their own beyond a `README.md`.
1935
+ >
1936
+ > Because `ai-toolkit install` links every core skill, installing a language
1937
+ > pack put **zero** files on disk. Measured on both runtimes and all three
1938
+ > profiles: `(0 file items)` every time.
1939
+ >
1940
+ > **If you used one of these packs, you lose nothing.** The skill it named is
1941
+ > already installed and triggers on the same file types it always did — open a
1942
+ > `.rs` file and `rust-patterns` still loads.
1943
+ >
1944
+ > Full measurement and the rule that now prevents a repeat:
1945
+ > [`no-op-plugin-packs-removed-20260727.md`](no-op-plugin-packs-removed-20260727.md).
1946
+ >
1947
+ > The document below is preserved as written on 2026-03-29.
1948
+
1803
1949
  ---
1804
1950
 
1805
- # Implementation Plan: Native Tool Output Filter
1951
+ ## Overview
1806
1952
 
1807
- ## Status
1953
+ Language packs are domain-scoped plugin packs that provide knowledge skills for specific programming languages. Each pack contains a single knowledge skill with idiomatic patterns, error handling, testing conventions, common frameworks, and performance tips.
1808
1954
 
1809
- Completed on 2026-07-23 after user approval.
1955
+ ## Available Packs
1810
1956
 
1811
- Completion evidence:
1957
+ | Pack | Skill | Language | Key Topics |
1958
+ |------|-------|----------|------------|
1959
+ | `rust-pack` | `rust-patterns` | Rust | Ownership, borrowing, Cargo, tokio, serde |
1960
+ | `java-pack` | `java-patterns` | Java | Records, sealed classes, Spring Boot, JUnit 5 |
1961
+ | `csharp-pack` | `csharp-patterns` | C# / .NET | Nullable refs, async/await, ASP.NET Core, EF Core |
1962
+ | `kotlin-pack` | `kotlin-patterns` | Kotlin | Coroutines, DSLs, sealed classes, Ktor, MockK |
1963
+ | `swift-pack` | `swift-patterns` | Swift / iOS | Protocol-oriented, SwiftUI, async/await, SPM |
1964
+ | `ruby-pack` | `ruby-patterns` | Ruby | Blocks, Rails conventions, RSpec, ActiveRecord |
1812
1965
 
1813
- - 69 focused Python tests pass, including the production-wrapper benchmark.
1814
- - The 100-sample cold wrapper measures 63.565 ms p95 against the 75 ms gate.
1815
- - The 8 MiB profile case measures 4.354 ms p95 and 8,792,932 peak traced
1816
- bytes against the 150 ms and 41,943,040 byte gates.
1817
- - The strict repository validator reports 44 agents, 108 skills, and 1477
1818
- tests with zero errors or warnings.
1819
- - Ruff, mypy, ShellCheck, skill audit, generated artifacts, and the final
1820
- repository test gate pass for the changed surface.
1966
+ ## Skill Content Sections
1821
1967
 
1822
- ## Context
1968
+ Each language skill follows a consistent structure:
1823
1969
 
1824
- `ai-toolkit` currently controls assistant response length and reports real
1825
- Claude session tokens, but it does not transform live tool output before that
1826
- output reaches the model. The requested feature is an original, MIT-licensed,
1827
- dependency-free implementation inside `ai-toolkit`. RTK is research input only:
1828
- no runtime dependency, vendoring, translated code, copied filters, fixtures,
1829
- regex tables, CLI names, or configuration keys.
1970
+ 1. **Project Structure** standard directory layout and build tool configuration
1971
+ 2. **Idioms / Code Style** language-specific patterns and conventions
1972
+ 3. **Error Handling** error types, patterns, and best practices
1973
+ 4. **Testing Patterns** test frameworks, assertion libraries, mocking
1974
+ 5. **Common Libraries / Frameworks** ecosystem essentials
1975
+ 6. **Performance Tips** optimization techniques and profiling
1976
+ 7. **Build / Package Management** — dependency management and CI
1830
1977
 
1831
- The first native integration targets Claude Code because current Claude hooks
1832
- support replacing successful tool output through
1833
- `PostToolUse.hookSpecificOutput.updatedToolOutput`. The transformer remains
1834
- strictly post-execution and cannot alter the command, arguments, environment,
1835
- working directory, permission decision, exit status, or signal.
1978
+ ## How Knowledge Skills Work
1836
1979
 
1837
- This feature is separate from MCP `tools/list` description trimming. Hooks can
1838
- transform an executed tool result, but they do not intercept MCP catalog
1839
- metadata. [PATH: kb/history/completed/f2-mcp-trim-spike-20260504.md]
1840
- [PATH: kb/planning/mcp-context-trim-v4-prd.md]
1980
+ These skills have `user-invocable: false` in their frontmatter, meaning they are NOT slash commands. Instead, Claude loads them contextually when the conversation topic matches the skill's description trigger.
1841
1981
 
1842
- Relevant local boundaries:
1982
+ For example, when a user asks "How do I handle errors in Rust?", Claude automatically loads `rust-patterns` to provide idiomatic Rust error handling guidance.
1843
1983
 
1844
- - Fixed lifecycle enforcement belongs in hooks. [PATH: CLAUDE.md:10]
1845
- - The current safety guards run in `PreToolUse`. [PATH: app/hooks.json:37]
1846
- - Hook runtime Python helpers are deployed explicitly.
1847
- [PATH: scripts/install_steps/hooks.py:71]
1848
- - Runtime hook schemas differ by editor.
1849
- [PATH: kb/reference/hooks-catalog.md:571]
1850
- - Existing output/token work intentionally uses native mechanisms.
1851
- [PATH: kb/history/completed/output-token-discipline-plan-20260504.md]
1852
- - Claude hook contract:
1853
- <https://code.claude.com/docs/en/hooks>
1984
+ ## Requesting New Language Packs
1854
1985
 
1855
- ## Scope
1986
+ File an issue with the `language-pack` label. Include:
1987
+ - Language name
1988
+ - Key topics to cover
1989
+ - Popular frameworks/libraries to include
1856
1990
 
1857
- ### Included
1991
+ ---
1858
1992
 
1859
- - Python standard library implementation under `scripts/`.
1860
- - Pure post-execution transformation of successful textual Bash output.
1861
- - `off`, `observe`, and `safe` modes.
1862
- - Claude Code integration through `PostToolUse.updatedToolOutput`.
1863
- - Manual CLI for fixture inspection, status, recovery, and cleanup.
1864
- - Two initial deterministic profiles:
1865
- - `repeat-lines`: aggregate adjacent identical non-diagnostic lines and state
1866
- their multiplicity.
1867
- - `tap-success`: compact valid successful TAP while retaining plan,
1868
- directives, comments, totals, duration, and all diagnostic material.
1869
- - Byte and line savings, latency, outcome, profile ID, and profile version.
1870
- - Exact, bounded, session-scoped raw recovery when `safe` mode is enabled.
1871
- - Capability-gated adapters for additional runtimes after Phase 2.
1993
+ ## kb/history/completed/mcp-context-trim-v4-prd-obsoleted-20260727.md
1872
1994
 
1873
- ### Excluded
1995
+ ---
1996
+ title: "PRD: MCP Context Trim v4.0 — Local Proxy with Description Compression"
1997
+ category: planning
1998
+ service: ai-toolkit
1999
+ tags:
2000
+ - mcp
2001
+ - proxy
2002
+ - tool-descriptions
2003
+ - jsonrpc
2004
+ - tokens
2005
+ - v4
2006
+ doc_type: plan
2007
+ status: obsoleted
2008
+ created: "2026-05-04"
2009
+ last_updated: "2026-07-27"
2010
+ completion: "0% — never started, and no longer worth starting"
2011
+ target_milestone: "v4.0 (abandoned)"
2012
+ predecessor:
2013
+ - "kb/history/completed/output-token-discipline-plan-20260504.md"
2014
+ - "kb/history/completed/f2-mcp-trim-spike-20260504.md"
2015
+ description: "ABANDONED 2026-07-27. Local MCP proxy that would compress tool descriptions before they reach the model. Never built. Claude Code now defers MCP tool schemas by default — the catalog costs ~120 tokens of tool names, with schemas fetched on demand — so the 8-15k per-turn overhead this PRD was written to remove no longer exists. Kept as the record of a plan the platform solved first."
2016
+ ---
2017
+
2018
+ # PRD: MCP Context Trim v4.0 — ABANDONED
2019
+
2020
+ > **Abandoned 2026-07-27, never implemented.**
2021
+ >
2022
+ > **Why:** the premise expired. This PRD is built on one measured claim — that
2023
+ > MCP tool descriptions sit in every turn's system prompt, costing 8–15k tokens
2024
+ > per turn. Claude Code now **defers MCP tool schemas by default**: the model
2025
+ > receives roughly 120 tokens of tool *names*, and full schemas are fetched on
2026
+ > demand through tool search when a task actually needs one.
2027
+ > ([Claude Code docs — context window](https://code.claude.com/docs/en/context-window),
2028
+ > `ENABLE_TOOL_SEARCH=auto|false` controls the older eager behaviour.)
2029
+ >
2030
+ > The overhead this proxy was designed to remove is already gone. Building it
2031
+ > now would add a supervised local daemon, an `.mcp.json` rewrite, a rollback
2032
+ > path and five pre-mortem failure modes in order to compress a 120-token
2033
+ > catalog.
2034
+ >
2035
+ > **How it was caught:** during the 2026-07-27 token-reduction review, a
2036
+ > measurement of 1189 real sessions put the median startup context at 22,175
2037
+ > tokens against ~7,850 in the documented reference shape. Attributing that gap
2038
+ > showed the excess was skill and agent descriptions and rule files — not MCP.
2039
+ > The MCP catalog was already deferred, exactly as the docs describe. Full
2040
+ > context: [`tool-output-token-reduction-closed-20260727.md`](tool-output-token-reduction-closed-20260727.md).
2041
+ >
2042
+ > **What survives:** nothing in the architecture below is reusable, because it
2043
+ > exists to solve a problem the host now solves. What survives is the process
2044
+ > note — this PRD sat in `kb/planning/` for nearly three months while the
2045
+ > platform shipped the fix, and nobody re-checked the premise. A plan blocked on
2046
+ > a host limitation should carry a re-validation date, not wait indefinitely.
2047
+ >
2048
+ > Everything below is the document as written on 2026-05-04. It is preserved
2049
+ > unedited so the reasoning stays auditable.
2050
+
2051
+ ---
2052
+
2053
+ **Status:** Proposed *(as of 2026-05-04; see abandonment note above)*
2054
+ **Target milestone:** v4.0
2055
+ **Carved out of:** [`output-token-discipline-plan-20260504.md`](output-token-discipline-plan-20260504.md) (was Feature 2)
2056
+ **Spike basis:** [`f2-mcp-trim-spike-20260504.md`](f2-mcp-trim-spike-20260504.md)
1874
2057
 
1875
- - RTK binaries, libraries, source code, filters, fixtures, configuration, or
1876
- branding.
1877
- - Command rewriting, `sh -c`, shell parsing, permission decisions, or command
1878
- execution by the filter.
1879
- - LLM-generated summaries or network calls.
1880
- - Project-defined regex filters in the first release.
1881
- - Failed commands, non-empty `stderr`, signals, TTY/streaming output, binary or
1882
- invalid text, pipes, redirects, security scanners, dependency audits,
1883
- deployment, migrations, permission failures, and destructive-command
1884
- diagnostics.
1885
- - `Read`, web results, arbitrary MCP results, and MCP `tools/list`.
1886
- - Claims that byte reduction equals billed-token or whole-session savings.
2058
+ ## Problem
2059
+
2060
+ MCP server tool descriptions are injected into every model turn's system prompt. With ~100 tools across 7 typical servers, descriptions consume 8–15k tokens per turn — pure overhead, paid every message. Examples observed in users' configs:
2061
+
2062
+ - `dart-mcp-server` ~30 tools with multi-paragraph descriptions
2063
+ - `filesystem` verbose paths and example sections
2064
+ - `pencil` "IMPORTANT" stanzas repeated across tools
2065
+ - `jira-mcp` long `Use this tool to…` boilerplate
2066
+
2067
+ The v3.2.0 output-discipline plan attempted to solve this with a hook-based trimmer. The spike conducted 2026-05-04 proved Claude Code hooks do not expose `tools/list` metadata or the system-prompt tool catalog. The only viable architecture is a local MCP proxy.
2068
+
2069
+ ## Goal
2070
+
2071
+ Reduce MCP-description overhead by ≥40% per server, with **zero** loss of parameter schemas, required fields, or discrimination signals (`not`, `never`, `only`, `except`, `unless`).
2072
+
2073
+ ## Non-goals
2074
+
2075
+ - Modifying tool **call** behavior (only descriptions)
2076
+ - Compressing user-facing prompts or completions
2077
+ - Replacing or rewriting upstream MCP servers
2078
+ - Touching MCP servers we do not control
2079
+
2080
+ ## Architecture
2081
+
2082
+ ### Proxy topology
2083
+
2084
+ ```
2085
+ Claude Code ──stdio──▶ ai-toolkit MCP proxy ──stdio/SSE──▶ upstream MCP server
2086
+
2087
+ └─ rewrites tools/list response
2088
+ passes through tools/call unchanged
2089
+ ```
2090
+
2091
+ One proxy process per upstream server, supervised by `ai-toolkit mcp-trim daemon` (or equivalent). User's `~/.claude/.mcp.json` is rewritten by `ai-toolkit install` (opt-in) to point Claude Code at the proxy instead of upstream — proxy reads the original target from a sidecar config.
2092
+
2093
+ ### Required components
2094
+
2095
+ | Component | Purpose |
2096
+ |-----------|---------|
2097
+ | `scripts/mcp_proxy_server.py` | JSON-RPC 2.0 proxy. Reads stdin, forwards to upstream over stdio or SSE, intercepts `tools/list` response, rewrites descriptions. Stdlib-only. |
2098
+ | `scripts/mcp_description_trimmer.py` | Pure function library: `trim(description: str) → str`. Reused from heuristics below. Stdlib-only. |
2099
+ | `scripts/mcp_proxy_config.py` | Reads `~/.softspark/ai-toolkit/mcp-proxy/servers.json`, validates upstream targets, generates supervisord/launchd config. |
2100
+ | `app/hooks/mcp-proxy-health.sh` | SessionStart hook — verifies all configured proxies responsive; fall through (warn, do not block) if any down. |
2101
+ | `app/skills/mcp-trim/SKILL.md` | Knowledge skill: how to enable, opt out, audit savings. |
2102
+ | `bin/ai-toolkit-mcp-trim` | CLI: `enable`, `disable`, `status`, `audit` (per-server token savings report). |
2103
+ | `tests/test_mcp_proxy.bats` | Integration tests with mock upstream MCP servers. |
2104
+ | `tests/test_mcp_trimmer.bats` | Unit tests for description trim heuristics on captured fixtures. |
2105
+
2106
+ ### Compression heuristics (from spike)
2107
+
2108
+ Applied to each tool description in `tools/list` response:
2109
+
2110
+ - Drop example sections >40 chars
2111
+ - Collapse `Use this server to…` / `Use this tool to…` boilerplate to minimum form preserving intent
2112
+ - Drop duplicate occurrences of tool name in its own description
2113
+ - **Preserve bytewise:** `inputSchema.properties[*].description`, `required`, `enum` values, URL/path identifiers
2114
+ - **Never strip:** the words `not`, `never`, `only`, `except`, `unless` — these carry "when NOT to use" signals
2115
+ - Target: ≥40% length reduction, 0% schema loss
2116
+
2117
+ ### Failure modes & rollback
2118
+
2119
+ | Scenario | Behavior |
2120
+ |----------|----------|
2121
+ | Proxy crashes mid-session | `mcp-proxy-health.sh` detects on next SessionStart, prints warning, suggests `ai-toolkit mcp-trim disable <server>` |
2122
+ | Upstream MCP server changes its tool catalog | Proxy passes through unchanged tools (no cached schema), warns once if a tool's description was previously trimmed |
2123
+ | Trimmer produces malformed JSON | Proxy falls through to upstream response unchanged, logs to `~/.softspark/ai-toolkit/mcp-proxy/error.log` |
2124
+ | User wants to bypass | `AI_TOOLKIT_MCP_TRIM_DISABLE=1` env var → proxies pass everything through unchanged |
2125
+ | User wants to fully uninstall | `ai-toolkit mcp-trim disable` reverts `~/.claude/.mcp.json` to original upstream targets |
2126
+
2127
+ ### Migration of existing user `.mcp.json`
2128
+
2129
+ `ai-toolkit mcp-trim enable` does:
2130
+
2131
+ 1. Backup `~/.claude/.mcp.json` → `~/.softspark/ai-toolkit/mcp-proxy/.mcp.json.bak.<timestamp>`
2132
+ 2. Read each server entry, store in `~/.softspark/ai-toolkit/mcp-proxy/servers.json`
2133
+ 3. Rewrite each entry to point at the local proxy (with sidecar `target` field)
2134
+ 4. Spawn supervisor (per-OS: launchd on macOS, systemd on Linux, scheduled task on Windows)
2135
+ 5. Verify each upstream reachable via proxy, abort + restore backup on any failure
2136
+
2137
+ ## Out-of-scope decisions (rejected mid-spike)
2138
+
2139
+ | Option | Why rejected |
2140
+ |--------|--------------|
2141
+ | Pre-install rewrite of `.mcp.json` only | MCP spec sources descriptions from server runtime, not config — wouldn't take effect |
2142
+ | Source-side forks of MCP servers | Doesn't help users with custom servers; high maintenance |
2143
+ | F2-lite observability tool | User decision 2026-05-04: tracking token waste without trimming is half-value; do the full thing in v4.0 |
2144
+ | Hook-based interception | Spike proved hooks cannot reach `tools/list` |
2145
+
2146
+ ## Success criteria
2147
+
2148
+ - ≥40% description-length reduction per server on the captured fixture set (jira, filesystem, dart, pencil)
2149
+ - Deep-equal `inputSchema` between trimmed and upstream — zero schema regression
2150
+ - Proxy adds <50ms per `tools/list` call (one-time per session)
2151
+ - Proxy adds <5ms per `tools/call` (passthrough overhead)
2152
+ - Round-trip correctness: every tool callable via proxy returns byte-identical result vs direct call
2153
+ - Zero MCP-skill regressions in `npm test` after enabling proxy in CI
2154
+ - Rollback (`ai-toolkit mcp-trim disable`) restores byte-identical original `.mcp.json`
2155
+
2156
+ ## Open questions
2157
+
2158
+ 1. Process supervision per-OS — launchd / systemd / scheduled-task wrappers, or a built-in `ai-toolkit-mcp-trimd` daemon binary?
2159
+ 2. SSE-mode upstreams (e.g., rag-mcp at `http://localhost:8081/mcp/sse`) — proxy listens on SSE locally too, or stdio-only with internal SSE client?
2160
+ 3. Description rewrites — static dictionary of "boilerplate phrases to drop" (faster, deterministic) vs LLM-based summarizer (more aggressive, less predictable)? Recommend static for v4.0, LLM as v4.1 stretch.
2161
+ 4. Config path — `~/.softspark/ai-toolkit/mcp-proxy/` (matches existing convention) or `~/.claude/mcp-proxy/` (closer to MCP config)? Recommend the former.
2162
+ 5. Telemetry — does this become an opt-in metric in `/briefing --tokens` ("MCP descriptions: 12.3k → 7.2k, saved 5.1k per turn")? Recommend yes.
2163
+
2164
+ ## Pre-mortem (failure scenarios to design against)
2165
+
2166
+ 1. **Proxy gets out of sync with upstream** — upstream adds a new tool, proxy doesn't know how to compress it → passthrough that tool's description unchanged, log warning
2167
+ 2. **Compression breaks tool discriminability** — model picks wrong tool because trimmed description lost the "use only when X" qualifier → the `not/never/only/except/unless` blacklist must be exhaustive; add per-server allowlists for false positives
2168
+ 3. **Multi-process race on `.mcp.json` rewrite** — two `ai-toolkit install` invocations clobber each other → file lock during enable/disable
2169
+ 4. **Proxy supervisor fails to start on user's machine** — different distro / no systemd → ai-toolkit doctor must detect and report; degrade to "MCP proxy unavailable, falling through" with no functionality loss
2170
+ 5. **User has custom MCP server we don't recognize** — must work without per-server schema; default heuristics must be safe enough for arbitrary servers
2171
+
2172
+ ## Estimate
2173
+
2174
+ - Architecture spike + working proxy prototype: 2 days
2175
+ - Production proxy + supervisor + config + CLI: 3 days
2176
+ - Test suite + fixtures + CI integration: 2 days
2177
+ - Documentation + migration guide + release notes: 1 day
2178
+
2179
+ **Total: ~8 working days** (1.5–2 weeks calendar time at typical pace)
2180
+
2181
+ ## Status
2182
+
2183
+ | Date | Status | Author |
2184
+ |------|--------|--------|
2185
+ | 2026-05-04 | PRD drafted from spike conclusions, carved out of v3.2.0 plan | claude |
2186
+ | 2026-07-27 | Abandoned without implementation. Claude Code began deferring MCP tool schemas by default, removing the per-turn overhead this proxy targeted. Moved from `kb/planning/` to `kb/history/completed/`. | claude |
2187
+
2188
+ ---
2189
+
2190
+ ## kb/history/completed/native-tool-output-filter-plan.md
2191
+
2192
+ ---
2193
+ title: "Implementation Plan: Native Tool Output Filter"
2194
+ category: planning
2195
+ service: ai-toolkit
2196
+ tags:
2197
+ - output-filter
2198
+ - hooks
2199
+ - recovery
2200
+ - performance
2201
+ - claude-code
2202
+ doc_type: plan
2203
+ status: completed
2204
+ created: "2026-07-23"
2205
+ last_updated: "2026-07-23"
2206
+ completed: "2026-07-23"
2207
+ completion: "100% of approved Claude Code scope; other runtimes remain manual-only by capability decision"
2208
+ shipped_in: "Unreleased"
2209
+ description: "Approved implementation plan and completion evidence for the original dependency-free ai-toolkit tool-output filter, including conservative profiles, exact recovery, telemetry, runtime capability gates, and adjacent repairs."
2210
+ ---
2211
+
2212
+ # Implementation Plan: Native Tool Output Filter
2213
+
2214
+ ## Status
2215
+
2216
+ Completed on 2026-07-23 after user approval.
2217
+
2218
+ Completion evidence:
2219
+
2220
+ - 69 focused Python tests pass, including the production-wrapper benchmark.
2221
+ - The 100-sample cold wrapper measures 63.565 ms p95 against the 75 ms gate.
2222
+ - The 8 MiB profile case measures 4.354 ms p95 and 8,792,932 peak traced
2223
+ bytes against the 150 ms and 41,943,040 byte gates.
2224
+ - The strict repository validator reports 44 agents, 108 skills, and 1477
2225
+ tests with zero errors or warnings.
2226
+ - Ruff, mypy, ShellCheck, skill audit, generated artifacts, and the final
2227
+ repository test gate pass for the changed surface.
2228
+
2229
+ ## Context
2230
+
2231
+ `ai-toolkit` currently controls assistant response length and reports real
2232
+ Claude session tokens, but it does not transform live tool output before that
2233
+ output reaches the model. The requested feature is an original, MIT-licensed,
2234
+ dependency-free implementation inside `ai-toolkit`. RTK is research input only:
2235
+ no runtime dependency, vendoring, translated code, copied filters, fixtures,
2236
+ regex tables, CLI names, or configuration keys.
2237
+
2238
+ The first native integration targets Claude Code because current Claude hooks
2239
+ support replacing successful tool output through
2240
+ `PostToolUse.hookSpecificOutput.updatedToolOutput`. The transformer remains
2241
+ strictly post-execution and cannot alter the command, arguments, environment,
2242
+ working directory, permission decision, exit status, or signal.
2243
+
2244
+ This feature is separate from MCP `tools/list` description trimming. Hooks can
2245
+ transform an executed tool result, but they do not intercept MCP catalog
2246
+ metadata. [PATH: kb/history/completed/f2-mcp-trim-spike-20260504.md]
2247
+ [PATH: kb/planning/mcp-context-trim-v4-prd.md]
2248
+
2249
+ Relevant local boundaries:
2250
+
2251
+ - Fixed lifecycle enforcement belongs in hooks. [PATH: CLAUDE.md:10]
2252
+ - The current safety guards run in `PreToolUse`. [PATH: app/hooks.json:37]
2253
+ - Hook runtime Python helpers are deployed explicitly.
2254
+ [PATH: scripts/install_steps/hooks.py:71]
2255
+ - Runtime hook schemas differ by editor.
2256
+ [PATH: kb/reference/hooks-catalog.md:571]
2257
+ - Existing output/token work intentionally uses native mechanisms.
2258
+ [PATH: kb/history/completed/output-token-discipline-plan-20260504.md]
2259
+ - Claude hook contract:
2260
+ <https://code.claude.com/docs/en/hooks>
2261
+
2262
+ ## Scope
2263
+
2264
+ ### Included
2265
+
2266
+ - Python standard library implementation under `scripts/`.
2267
+ - Pure post-execution transformation of successful textual Bash output.
2268
+ - `off`, `observe`, and `safe` modes.
2269
+ - Claude Code integration through `PostToolUse.updatedToolOutput`.
2270
+ - Manual CLI for fixture inspection, status, recovery, and cleanup.
2271
+ - Two initial deterministic profiles:
2272
+ - `repeat-lines`: aggregate adjacent identical non-diagnostic lines and state
2273
+ their multiplicity.
2274
+ - `tap-success`: compact valid successful TAP while retaining plan,
2275
+ directives, comments, totals, duration, and all diagnostic material.
2276
+ - Byte and line savings, latency, outcome, profile ID, and profile version.
2277
+ - Exact, bounded, session-scoped raw recovery when `safe` mode is enabled.
2278
+ - Capability-gated adapters for additional runtimes after Phase 2.
2279
+
2280
+ ### Excluded
2281
+
2282
+ - RTK binaries, libraries, source code, filters, fixtures, configuration, or
2283
+ branding.
2284
+ - Command rewriting, `sh -c`, shell parsing, permission decisions, or command
2285
+ execution by the filter.
2286
+ - LLM-generated summaries or network calls.
2287
+ - Project-defined regex filters in the first release.
2288
+ - Failed commands, non-empty `stderr`, signals, TTY/streaming output, binary or
2289
+ invalid text, pipes, redirects, security scanners, dependency audits,
2290
+ deployment, migrations, permission failures, and destructive-command
2291
+ diagnostics.
2292
+ - `Read`, web results, arbitrary MCP results, and MCP `tools/list`.
2293
+ - Claims that byte reduction equals billed-token or whole-session savings.
1887
2294
 
1888
2295
  ## Architecture
1889
2296
 
@@ -2302,53 +2709,185 @@ the savings threshold, and all unsafe paths remain exact passthrough.
2302
2709
 
2303
2710
  ---
2304
2711
 
2305
- ## kb/history/completed/offline-slm-profile-plan-20260411.md
2712
+ ## kb/history/completed/no-op-plugin-packs-removed-20260727.md
2306
2713
 
2307
2714
  ---
2308
- title: "Plan: Offline-First SLM Profile Lightweight Mode for Local Models"
2715
+ title: "Removed: Nine Plugin Packs That Installed Nothing"
2309
2716
  category: planning
2310
2717
  service: ai-toolkit
2311
2718
  tags:
2312
- - offline
2313
- - slm
2314
- - small-language-models
2315
- - ollama
2316
- - lm-studio
2317
- - profile
2318
- - context-optimization
2319
- - privacy
2320
- doc_type: plan
2719
+ - plugins
2720
+ - plugin-pack
2721
+ - measurement
2722
+ - postmortem
2723
+ - dead-code
2724
+ doc_type: postmortem
2321
2725
  status: completed
2322
- created: "2026-04-10"
2323
- last_updated: "2026-04-11"
2324
- completion: "100%"
2325
- completed: "2026-04-11"
2326
- description: "Lightweight profile for ai-toolkit optimized for Small Language Models (SLMs) running locally via Ollama, LM Studio, or similar. Compiles a minimal instruction set that fits within 4K-8K system prompt budgets while preserving critical safety guardrails. Targets air-gapped, privacy-first, and cost-sensitive development workflows."
2726
+ created: "2026-07-27"
2727
+ last_updated: "2026-07-27"
2728
+ shipped_in: "v4.20.0 (removal)"
2729
+ description: "Nine of eleven plugin packs installed zero files, because every asset they declared already ships in the core install. Measured across both runtimes and all three profiles. Records what was removed, what survived, why the authoring guidance produced the problem, and the check that now prevents a repeat."
2327
2730
  ---
2328
2731
 
2329
- # Plan: Offline-First SLM Profile Lightweight Mode for Local Models
2732
+ # Removed: Nine Plugin Packs That Installed Nothing
2330
2733
 
2331
- **Status:** Completed
2332
- **Completion:** 100%
2333
- **Completed:** 2026-04-11
2334
- **Created:** 2026-04-10
2335
- **Origin:** Enterprise IP security requirements (air-gapped environments), cost-sensitive solo developers, and the growing adoption of local models (Ollama, LM Studio, llamafile). Current toolkit emits 20K+ token system prompts that exceed SLM context windows and degrade small model performance.
2336
- **Estimated Effort:** 4-5 weeks (1 person)
2734
+ `csharp-pack`, `java-pack`, `kotlin-pack`, `ruby-pack`, `rust-pack`,
2735
+ `swift-pack`, `frontend-pack`, `research-pack`, `security-pack` — removed in
2736
+ v4.20.0. `memory-pack` and `enterprise-pack` stay.
2337
2737
 
2338
- ---
2738
+ ## The measurement
2339
2739
 
2340
- ## 1. Objective
2740
+ `ai-toolkit install` into a throwaway `HOME`, then `plugin install <pack>`, on
2741
+ each runtime. The number is what `plugin install` itself reports:
2341
2742
 
2342
- Create a `--profile offline-slm` install profile and a `scripts/compile_slm.py` compiler that produces a minimal, high-signal instruction set optimized for Small Language Models (8B-32B parameters). The compiled output preserves critical safety guardrails while stripping agent orchestration, multi-agent coordination, and complex skill routing that SLMs cannot handle.
2743
+ | Pack | claude | codex |
2744
+ |---|---:|---:|
2745
+ | `csharp-pack` | 0 | 0 |
2746
+ | `java-pack` | 0 | 0 |
2747
+ | `kotlin-pack` | 0 | 0 |
2748
+ | `ruby-pack` | 0 | 0 |
2749
+ | `rust-pack` | 0 | 0 |
2750
+ | `swift-pack` | 0 | 0 |
2751
+ | `research-pack` | 0 | 0 |
2752
+ | `security-pack` | 0 | 0 |
2753
+ | `frontend-pack` | 0 | **1** |
2754
+ | **`memory-pack`** | **4** | **4** |
2755
+ | **`enterprise-pack`** | **2** | **2** |
2756
+
2757
+ Cross-checked against the filesystem, not just the reported count: after core
2758
+ install (108 skills, 44 agents, 4742 characters of hook config), installing
2759
+ `rust-pack`, `security-pack`, `research-pack` or any language pack produced
2760
+ `+0` skills, `+0` agents, `+0` bytes of `settings.json` and `+0` files under
2761
+ `~/.softspark`.
2762
+
2763
+ Profiles make no difference. `minimal`, `standard` and `strict` all install the
2764
+ same 108 skills and 44 agents, and packs add `+0` to each.
2343
2765
 
2344
- **Key design principles:**
2345
- - **Token budget** — compiled output fits within 4K tokens (system prompt), with optional 8K mode for larger SLMs
2346
- - **Safety-preserved** Constitution Articles I-V always included (non-negotiable)
2347
- - **Single-agent focus** — no multi-agent orchestration, no /swarm, no /teams
2348
- - **Deterministic compilation** same input same output, no LLM involved in compilation
2349
- - **Model-aware** — detects model size from Ollama API or manual flag and adjusts verbosity
2350
- - **Platform-agnostic** outputs plain markdown consumable by any local inference engine
2351
- - **Hooks stripped** SLM providers don't support lifecycle hooks; rules compile into system prompt
2766
+ ## Why
2767
+
2768
+ Every one of the nine declared only assets that already ship in core:
2769
+
2770
+ | Pack | Declared | All present in core? |
2771
+ |---|---|---|
2772
+ | `rust-pack` | `rust-patterns` | yes |
2773
+ | `security-pack` | `review`, `security-patterns`, `panic`, `security-auditor`, `security-architect`, `code-reviewer` | yes |
2774
+ | `research-pack` | `docs`, `research-mastery`, `plan`, `technical-researcher`, `fact-checker`, `search-specialist` | yes |
2775
+
2776
+ Since `ai-toolkit install` links every core skill and agent, a manifest that
2777
+ names only core assets resolves to a set of things already installed. There is
2778
+ nothing left to do, so nothing is done.
2779
+
2780
+ Eight of the nine owned no file but `README.md`. `security-pack`'s two hooks
2781
+ were core's `guard-destructive.sh` and `quality-gate.sh`; `research-pack`'s was
2782
+ core's `user-prompt-submit.sh`.
2783
+
2784
+ ## The one that was not quite zero
2785
+
2786
+ `frontend-pack` installed exactly one file, on codex only:
2787
+ `plugin-frontend-pack-post-tool-use.sh`. The pack owned no such file — it
2788
+ declared core's `post-tool-use.sh`, which core's codex surface does not install,
2789
+ so the pack copied it in under a pack-prefixed name.
2790
+
2791
+ That is a generic hook wearing a domain label, not frontend functionality. It
2792
+ was removed with the pack. **If `post-tool-use` should run on codex, it belongs
2793
+ in the core codex hook set**, and adding it there is a separate, honest change —
2794
+ not a side effect of installing a pack named after a UI framework.
2795
+
2796
+ ## The authoring rule that caused this
2797
+
2798
+ `app/skills/plugin-creator/SKILL.md` told pack authors:
2799
+
2800
+ > **MUST** reference existing toolkit assets before duplicating — packs extend,
2801
+ > they do not fork
2802
+
2803
+ Read literally against a core install that ships everything, that instruction
2804
+ produces a no-op every time. It was correct about avoiding forks and silent
2805
+ about the pack needing to add anything. Nine packs followed it exactly.
2806
+
2807
+ The rule now reads that a pack **must install something the core install does
2808
+ not**, with the verification spelled out, and the validation checklist carries a
2809
+ line item requiring a non-zero file count on every runtime the pack claims.
2810
+
2811
+ ## What survived, and what users lose
2812
+
2813
+ **Nothing.** Every skill and agent the nine packs named is a core asset, still
2814
+ present, still installed, still triggering on the same conditions. A Rust
2815
+ developer who had `rust-pack` installed keeps `rust-patterns`, because it was
2816
+ never in the pack.
2817
+
2818
+ The two remaining packs are the two that own files:
2819
+
2820
+ - `memory-pack` — two hooks, `init_db.py`, `strip_private.py`, and its own
2821
+ `mem-search` skill. Verified working the same day: driving
2822
+ `observation-capture.sh` with a real payload wrote a row to the SQLite store.
2823
+ - `enterprise-pack` — `status-line.sh` and `output-style.sh`, both its own.
2824
+
2825
+ ## Process note
2826
+
2827
+ The removal was nearly made on a wrong measurement. The first pass concluded
2828
+ "nine no-ops on every editor" after testing only four packs on the claude
2829
+ surface. `tests/test_plugin.bats` contradicted it by asserting that
2830
+ `frontend-pack` creates a file on codex — the test was right and the
2831
+ measurement was incomplete. The full 11 × 2 matrix was only then run.
2832
+
2833
+ The existing test suite caught an error in a fresh measurement. That is worth
2834
+ remembering next time a test looks like it is merely in the way of a cleanup.
2835
+
2836
+ ## Related
2837
+
2838
+ - [Plugin Pack Conventions](../../reference/plugin-pack-conventions.md) — the rule this postmortem installed
2839
+ - [Language Packs (removed)](language-packs-removed-20260727.md) — the reference doc for six of the nine
2840
+ - [rtk-pack Retirement](rtk-pack-retirement-20260727.md) — the pack removed the day before, for a different reason
2841
+
2842
+ ---
2843
+
2844
+ ## kb/history/completed/offline-slm-profile-plan-20260411.md
2845
+
2846
+ ---
2847
+ title: "Plan: Offline-First SLM Profile — Lightweight Mode for Local Models"
2848
+ category: planning
2849
+ service: ai-toolkit
2850
+ tags:
2851
+ - offline
2852
+ - slm
2853
+ - small-language-models
2854
+ - ollama
2855
+ - lm-studio
2856
+ - profile
2857
+ - context-optimization
2858
+ - privacy
2859
+ doc_type: plan
2860
+ status: completed
2861
+ created: "2026-04-10"
2862
+ last_updated: "2026-04-11"
2863
+ completion: "100%"
2864
+ completed: "2026-04-11"
2865
+ description: "Lightweight profile for ai-toolkit optimized for Small Language Models (SLMs) running locally via Ollama, LM Studio, or similar. Compiles a minimal instruction set that fits within 4K-8K system prompt budgets while preserving critical safety guardrails. Targets air-gapped, privacy-first, and cost-sensitive development workflows."
2866
+ ---
2867
+
2868
+ # Plan: Offline-First SLM Profile — Lightweight Mode for Local Models
2869
+
2870
+ **Status:** Completed
2871
+ **Completion:** 100%
2872
+ **Completed:** 2026-04-11
2873
+ **Created:** 2026-04-10
2874
+ **Origin:** Enterprise IP security requirements (air-gapped environments), cost-sensitive solo developers, and the growing adoption of local models (Ollama, LM Studio, llamafile). Current toolkit emits 20K+ token system prompts that exceed SLM context windows and degrade small model performance.
2875
+ **Estimated Effort:** 4-5 weeks (1 person)
2876
+
2877
+ ---
2878
+
2879
+ ## 1. Objective
2880
+
2881
+ Create a `--profile offline-slm` install profile and a `scripts/compile_slm.py` compiler that produces a minimal, high-signal instruction set optimized for Small Language Models (8B-32B parameters). The compiled output preserves critical safety guardrails while stripping agent orchestration, multi-agent coordination, and complex skill routing that SLMs cannot handle.
2882
+
2883
+ **Key design principles:**
2884
+ - **Token budget** — compiled output fits within 4K tokens (system prompt), with optional 8K mode for larger SLMs
2885
+ - **Safety-preserved** — Constitution Articles I-V always included (non-negotiable)
2886
+ - **Single-agent focus** — no multi-agent orchestration, no /swarm, no /teams
2887
+ - **Deterministic compilation** — same input → same output, no LLM involved in compilation
2888
+ - **Model-aware** — detects model size from Ollama API or manual flag and adjusts verbosity
2889
+ - **Platform-agnostic** — outputs plain markdown consumable by any local inference engine
2890
+ - **Hooks stripped** — SLM providers don't support lifecycle hooks; rules compile into system prompt
2352
2891
 
2353
2892
  ---
2354
2893
 
@@ -4338,6 +4877,201 @@ designed for.
4338
4877
 
4339
4878
  ---
4340
4879
 
4880
+ ## kb/history/completed/tool-output-token-reduction-closed-20260727.md
4881
+
4882
+ ---
4883
+ title: "Closed: Tool-Output Token Reduction — Three Attempts, One Ceiling"
4884
+ category: planning
4885
+ service: ai-toolkit
4886
+ tags:
4887
+ - token-reduction
4888
+ - measurement
4889
+ - postmortem
4890
+ - prompt-caching
4891
+ - context-window
4892
+ - closed-line-of-work
4893
+ doc_type: postmortem
4894
+ status: completed
4895
+ created: "2026-07-27"
4896
+ last_updated: "2026-07-27"
4897
+ description: "Closes the tool-output token-reduction line of work after a third measurement. Decomposes 1189 real sessions by cost: 84% is context being fed to the model, 14.7% is responses. Tool output is a small lever by construction and three independent attempts have now hit the same ceiling. Records what shipped (a 20.2% rag-mcp response trim, worth 0.49% of cost), what was killed by its own kill number, and the three measurement errors made on the way."
4898
+ ---
4899
+
4900
+ # Closed: Tool-Output Token Reduction
4901
+
4902
+ **Read this before proposing a fourth attempt.**
4903
+
4904
+ Three independent efforts have tried to cut tokens by shrinking what tools
4905
+ return. All three were competently built. All three measured out near zero.
4906
+
4907
+ | Attempt | Shipped | Measured saving |
4908
+ |---|---|---:|
4909
+ | [Native tool-output filter](output-filter-retirement-20260726.md) | v4.16.0, removed v4.17.0 | **0.0000%** |
4910
+ | [rtk-pack](rtk-pack-retirement-20260727.md) | v4.18.0, removed v4.19.0 | **0.0615%** |
4911
+ | This review's only clean win (rag-mcp response trim) | rag-mcp, 2026-07-27 | **0.49%** |
4912
+
4913
+ This is not three unlucky implementations. It is one structural fact, measured
4914
+ three different ways.
4915
+
4916
+ ## Where the money actually is
4917
+
4918
+ 1189 sessions with traffic, 83,352 assistant turns, priced at Opus list rates:
4919
+
4920
+ | Component | Share of cost |
4921
+ |---|---:|
4922
+ | `cache_read` | **63.1%** |
4923
+ | `cache_creation` | 20.9% |
4924
+ | `output` | 14.7% |
4925
+ | `input` (uncached) | 1.3% |
4926
+
4927
+ **84% of cost is feeding context to the model.** Responses are 14.7%. That
4928
+ closes "make the model write less" as a serious lever — the whole `brand-voice`
4929
+ concise mode plays for a seventh of the bill.
4930
+
4931
+ Cache hit rate is **97.4%**. Published guidance treats 80–95% as the achievable
4932
+ band, so there is nothing to win in cache tuning either.
4933
+
4934
+ Session shape: median 29 turns (mean 70.1), median peak context 71,276 tokens
4935
+ (mean 114,712), median startup context 22,175 tokens.
4936
+
4937
+ ## Why tool output cannot be the lever
4938
+
4939
+ Decomposed by amplification — every tool result is re-read on every turn that
4940
+ follows it, so a result's true cost is its size times the turns remaining:
4941
+
4942
+ | Category | Share of `cache_read` |
4943
+ |---|---:|
4944
+ | Fixed startup prelude | 12.4% |
4945
+ | `Read` results | 15.6% |
4946
+ | `Bash` results | 6.7% |
4947
+ | `rag-mcp` results | 3.8% |
4948
+ | Unattributed (assistant text, thinking, user messages, reminders) | ~61% |
4949
+
4950
+ Every tool in the toolbox, amplified across every turn, is **26.1%** of
4951
+ `cache_read`, and it is not compressible without losing what it says. The
4952
+ original Phase 0 calculation reached the same place from the other direction:
4953
+ tool results are 4.54% of input-token volume, so 4.54% is the arithmetic
4954
+ ceiling for any mechanism operating on them.
4955
+
4956
+ Raw tool-result bytes, 113 MB across 1308 session files:
4957
+
4958
+ | Tool | Share of bytes |
4959
+ |---|---:|
4960
+ | `Read` | 62.2% |
4961
+ | `Bash` | 26.1% |
4962
+ | `rag-mcp` (3 tools) | 7.6% |
4963
+ | everything else | <2% each |
4964
+
4965
+ ## What shipped
4966
+
4967
+ **rag-mcp response compaction** — `compact_payload()` in
4968
+ `app/rag-mcp-server/routes/kb_search.py`, applied to `smart_query`,
4969
+ `hybrid_search_kb` and `get_document`, plus both sides of the smart_query cache
4970
+ so a hit and a miss return identical bytes.
4971
+
4972
+ Verified by running the shipped function over 1356 real responses captured from
4973
+ session logs: **20.2% smaller, with no field the agent acts on removed.**
4974
+ That is 0.77% of `cache_read`, **0.49% of total cost**.
4975
+
4976
+ It drops request echo (`use_hyde`/`use_crag`/`use_multi_hop`), null result
4977
+ columns, `_from_cache: false`, `total_documents_used` when it equals the result
4978
+ count, and the part of `source_documents_used` that merely repeats
4979
+ `results[].kb_id`. It deliberately keeps `file_path` (addresses Read/Edit, where
4980
+ `kb_id` addresses get_document), `routing` (the only signal for which pipeline
4981
+ ran), `score: 0.0`, and empty result sets. 16 unit tests, most of them asserting
4982
+ what must survive rather than what gets removed.
4983
+
4984
+ ## What was killed, and by what
4985
+
4986
+ A kill number was published before the work: *if the shipped changes do not cut
4987
+ `cache_read` by 3%, stop and do not proceed to the behavioural changes.*
4988
+
4989
+ Result: **0.79%.** The threshold was not met, and the remaining items were not
4990
+ built. The kill number did its job — this is the first of the three attempts
4991
+ where it bound before code was written rather than after it shipped.
4992
+
4993
+ ## Three measurement errors, and what they cost
4994
+
4995
+ Recorded because each one nearly produced a wrong decision, and because two of
4996
+ them are the same class of error that produced the previous two failures.
4997
+
4998
+ **1. Duplicate reads: 11.1% was actually 0.1%.** The first pass keyed duplicate
4999
+ detection on `file_path` alone, counting re-reads of *different ranges* of the
5000
+ same file as waste. Re-keyed on `(file_path, offset, limit)`:
5001
+
5002
+ | Key | Duplicates | Bytes | Share of `Read` |
5003
+ |---|---:|---:|---:|
5004
+ | path only (wrong) | 1754 | 7,787,530 | 11.1% |
5005
+ | path + offset + limit (right) | **36** | **90,975** | **0.1%** |
5006
+
5007
+ A whole planned deliverable — a session-scoped dedup hook, with a designed
5008
+ mitigation for the post-compaction re-read hazard — rested on that 11.1%. It
5009
+ does not exist.
5010
+
5011
+ **2. A 58% "trim" that was deleting document content.** An aggressive variant of
5012
+ the rag-mcp compaction measured 58% smaller. It was whitelisting top-level keys
5013
+ and thereby dropping `content` — which for `get_document` *is* the document,
5014
+ 30.5% of all bytes those endpoints return. Not a trim; data loss that looked
5015
+ like a win. The honest figure is 20.2%.
5016
+
5017
+ **3. "77.5% of the rag-mcp response is overhead."** Roughly half of that
5018
+ non-content mass is `kb_id`, `file_path`, `title` and `score` — fields the agent
5019
+ uses. Removable overhead is about 20%, not 77%.
5020
+
5021
+ The common thread: **every one of these errors made the opportunity look bigger
5022
+ than it is, and every one was caught only by decomposing before building.** The
5023
+ filter retirement drew the same conclusion about premise validation; rtk-pack
5024
+ drew it about installing the artifact. This adds a third: decompose the metric
5025
+ before trusting its headline.
5026
+
5027
+ ## What is left, and why it was not taken
5028
+
5029
+ | Option | Value | Why not |
5030
+ |---|---:|---|
5031
+ | Model routing | tens of % | Ruled out by the maintainer — Opus 5 stays |
5032
+ | Trim the toolkit's own startup prelude | ~2.5% of cost | Ruled out — costs skill/agent discoverability |
5033
+ | `Read` with ranges instead of whole files | up to 10.4% of `cache_read` | The only remaining item of size, and **not quality-neutral**: it is a behavioural change whose effect on correctness cannot be measured automatically |
5034
+ | Unattributed ~61% of `cache_read` | unknown | Assistant text, thinking blocks, user messages, system reminders — no clean cut available |
5035
+
5036
+ For the record, the startup prelude was measured rather than guessed. Median
5037
+ startup context is 22,175 tokens against ~7,850 in the documented reference
5038
+ shape, and the gap is the toolkit's own:
5039
+
5040
+ | Component | Count | ~tokens |
5041
+ |---|---:|---:|
5042
+ | skill descriptions | 108 | 5,051 |
5043
+ | agent descriptions | 44 | 2,750 |
5044
+ | project rules | 5 | 3,802 |
5045
+ | global rules | 6 | 3,133 |
5046
+ | `CLAUDE.md` files | 3 | 2,338 |
5047
+ | **total** | | **17,076** |
5048
+
5049
+ The tool built to reduce tokens is the single largest addition to every
5050
+ session's context. That is worth knowing, and it is still only 2.5% of cost,
5051
+ because the prelude is 12.4% of `cache_read` and only part of it is removable.
5052
+
5053
+ ## The rule this leaves behind
5054
+
5055
+ **Do not open a fourth tool-output token-reduction effort without first
5056
+ producing a measurement that beats 4.54%.** That is the ceiling on this workload
5057
+ and it has now been approached from three directions. Any proposal in this space
5058
+ must state, before any code, which share of *input token volume* it addresses —
5059
+ not which share of tool output, not which share of Bash bytes.
5060
+
5061
+ If token cost genuinely needs to come down, the levers that are actually large
5062
+ are model selection and turn count. Both are policy decisions, not engineering
5063
+ projects, and neither is in this line of work.
5064
+
5065
+ ## Related
5066
+
5067
+ - [Output Filter Retirement](output-filter-retirement-20260726.md) — attempt one, 0.0000%
5068
+ - [rtk-pack Retirement](rtk-pack-retirement-20260727.md) — attempt two, 0.0615%
5069
+ - [rtk Pack Integration](rtk-pack-integration-20260726.md) — the Phase 0 ceiling calculation
5070
+ - [MCP Context Trim v4.0 — abandoned](mcp-context-trim-v4-prd-obsoleted-20260727.md) — a fourth idea in this space, killed by the platform shipping the fix first
5071
+ - [Output & Token Discipline](output-token-discipline-plan-20260504.md) — the plan all of this descends from
5072
+
5073
+ ---
5074
+
4341
5075
  ## kb/howto/README.md
4342
5076
 
4343
5077
  ---
@@ -5438,354 +6172,90 @@ Examples:
5438
6172
  3. **AWS credential scope too broad** — User provides admin-level AWS profile. Mitigation: `credentials test` checks actual permissions, WARN if write access detected, suggest read-only IAM policy in docs.
5439
6173
  4. **Three providers = 3x maintenance** — Each provider's CLI evolves independently. Mitigation: abstract provider interface, single test matrix, version tracking per provider.
5440
6174
  5. **Terraform parsing incomplete** — HCL syntax is complex (modules, variables, conditionals). Mitigation: wrap `terraform show -json` instead of parsing HCL. Fallback to flat regex for projects without `terraform` CLI.
5441
- 6. **SARIF adoption low** — Users may not know how to use SARIF with GitHub. Mitigation: provide copy-paste GitHub Actions workflow in docs and `--explain` for onboarding.
5442
-
5443
- ---
5444
-
5445
- ## 12. Council Review Summary (2026-04-10)
5446
-
5447
- **Verdict:** CONDITIONAL FOR — implement with scope reduction.
5448
- **Confidence:** MEDIUM (weighted score: FOR 3.1 vs AGAINST 2.9)
5449
-
5450
- **Key insights applied to this plan:**
5451
- - [x] Timeline revised from 3-4 → 5-6 weeks
5452
- - [x] ~~Azure deferred to Milestone 3~~ → **reinstated: full 3-provider delivery**
5453
- - [x] SARIF v2.1.0 output added — essential for GitHub Advanced Security integration
5454
- - [x] Incremental scan mode added (`--changed`) — how developers actually use security tools
5455
- - [x] `terraform show -json` wrapper instead of HCL parsing — realistic path
5456
- - [x] Single config file `.cloud-security.json` (merged ignore + context)
5457
- - [x] `credentials init` interactive wizard — reduce onboarding friction
5458
- - [x] `--explain <rule-id>` for on-demand remediation guidance
5459
- - [x] Static mode as default — zero-setup first experience
5460
-
5461
- **Deferred to v2:**
5462
- - Kubernetes/container security (separate pack candidate)
5463
- - Secret scanning with entropy detection
5464
- - Compliance framework mapping (SOC2, PCI-DSS, NIST 800-53)
5465
- - Visual security dashboard in browser
5466
- - GitHub PR comment integration beyond SARIF
5467
- - Vendored YAML subset parser for CloudFormation YAML static scanning
5468
-
5469
- **Council strongest agreement:** False positive resolver is the killer feature and primary differentiator vs Checkov/Trivy/Prowler. No existing tool combines deterministic scanning with context-aware resolution.
5470
-
5471
- ---
5472
-
5473
- ## 13. Orchestration Review Summary (2026-04-10)
5474
-
5475
- **Agents:** tech-lead, security-architect, product-manager, code-reviewer (4 parallel)
5476
-
5477
- **Verdict:** Plan structurally complete (14/14 elements). Three P0 security blockers identified and resolved.
5478
-
5479
- **Applied changes:**
5480
-
5481
- | # | Action | Source | Priority | Applied? |
5482
- |---|--------|--------|----------|----------|
5483
- | 1 | Programmatic Bash allowlist | security-architect | P0 | Yes — allowlist.sh + agent integration |
5484
- | 2 | CI hardening (mktemp/trap/SARIF validation) | security-architect | P0 | Yes — CI examples rewritten |
5485
- | 3 | Suppression governance (justification + diff detection) | security-architect | P0 | Yes — schema + SUPPRESSION_CHANGED finding |
5486
- | 4 | Recursive descent parser for Firestore | code-reviewer | P1 | Yes — replaced regex approach, +1d estimate |
5487
- | 5 | SARIF `driver.rules[]` for GitHub annotations | code-reviewer | P1 | Yes — schema + success criteria |
5488
- | 6 | Task 4.1→3.2 numbering fix | tech-lead | P1 | Yes — renumbered |
5489
- | 7 | `terraform plan` execution risk documented | security-architect | P1 | Yes — only `show -json` allowed |
5490
- | 8 | `credentials init` deferred to M2 | code-reviewer | P2 | Yes — saves 1.5d in M1 |
5491
- | 9 | False positive resolver budgeted +2d/provider | code-reviewer | P2 | Yes — estimate updated |
5492
- | 10 | `SUPPRESSION_CHANGED` finding type | security-architect | P2 | Yes — in governance section |
5493
-
5494
- **Market positioning (product-manager):**
5495
- - Not competing with Checkov on check count (40 vs 3000)
5496
- - Competing on: zero-noise (false positive resolver), zero-setup (static-first), IDE-native (10 platforms), AI interpretation
5497
- - Target: developers in ai-toolkit ecosystem, not enterprise security teams
5498
- - Value as ecosystem feature, not standalone product
5499
-
5500
- **Timeline revision (code-reviewer):**
5501
- - 1 person: 6-7 weeks realistic (was 5-6)
5502
- - 2 people: 4-5 weeks (parallel GCP + AWS tracks)
5503
- - All 3 providers ship in 6 weeks — no conditional gates
5504
-
5505
- ---
5506
-
5507
- ## 14. Next Actions
5508
-
5509
- 1. [ ] Approve plan
5510
- 2. [ ] Implement `credentials` CLI command (1.1) + Bash allowlist
5511
- 3. [ ] Create `cloud-security-auditor` agent (1.2)
5512
- 4. [ ] Implement SARIF formatter + incremental scan (1.3)
5513
- 5. [ ] Implement `firebase-rules-audit` — recursive descent parser (2.1)
5514
- 6. [ ] Implement `cloud-functions-audit` + false positive resolver GCP (2.2, 2.3)
5515
- 7. [ ] Implement `aws-security-audit` + `terraform show -json` wrapper (3.1)
5516
- 8. [ ] Implement orchestrator + plugin pack + `credentials init` (3.2, 1.1b)
5517
- 9. [ ] Implement `azure-security-audit` + false positive resolver Azure (4.1)
5518
- 10. [ ] Full test suite (70+) + documentation + release
5519
-
5520
- ---
5521
-
5522
- **Last Updated:** 2026-04-10
5523
- **Council Reviewed:** 2026-04-10
5524
- **Orchestration Reviewed:** 2026-04-10 (4 agents: tech-lead, security-architect, product-manager, code-reviewer)
5525
-
5526
- ---
5527
-
5528
- ## kb/planning/drop-cascade-hooks-after-sunset.md
5529
-
5530
- ---
5531
- title: "Plan: Drop Cascade hooks after 2026-07-01 sunset"
5532
- category: planning
5533
- service: ai-toolkit
5534
- tags:
5535
- - windsurf
5536
- - devin
5537
- - cascade
5538
- - hooks
5539
- - deprecation
5540
- - cleanup
5541
- doc_type: plan
5542
- status: completed
5543
- created: "2026-06-10"
5544
- last_updated: "2026-07-10"
5545
- completion: "100%"
5546
- trigger_date: "2026-07-01"
5547
- description: "Completed cleanup of the deprecated Windsurf Cascade hooks generator after the 2026-07-01 sunset; Devin CLI .devin/hooks.v1.json is now the sole live hook surface."
5548
- ---
5549
-
5550
- # Plan: Drop Cascade hooks after 2026-07-01 sunset
5551
-
5552
- **Completed in v4.13.0 (2026-07-10).** The deprecated generator and install/test wiring were removed; the Devin hook generator remains.
5553
-
5554
- ## Why this exists
5555
-
5556
- Windsurf rebranded to Devin Desktop on 2026-06-02. The Cascade agent — and its
5557
- `.windsurf/hooks.json` hook surface (`agent_action_name`/`tool_info` format) — is
5558
- available **only through 2026-07-01**. Devin Local / Devin CLI do **not** read
5559
- `.windsurf/hooks.json` as a fallback.
5560
-
5561
- v4.8.0 already shipped the replacement: `generate_devin_hooks.py` emits
5562
- `.devin/hooks.v1.json` in the Claude-compatible format Devin CLI uses. During the
5563
- transition **both** generators run at `profile=full` so pre-sunset Cascade users
5564
- keep working. After 2026-07-01 the Cascade half is dead code and must be removed
5565
- (Constitution Art. VI.1 — no dead code).
5566
-
5567
- ## Trigger
5568
-
5569
- First ai-toolkit release **on or after 2026-07-01**. Do NOT do this earlier —
5570
- removing it before the sunset breaks Cascade users who are still on the old agent.
5571
-
5572
- ## Scope — remove the Cascade hooks surface
5573
-
5574
- 1. **Delete the generator:** `scripts/generate_windsurf_hooks.py`.
5575
- 2. **Unwire the install step:** in `scripts/install_steps/ai_tools.py`, remove the
5576
- `_try_generator("generate_windsurf_hooks", cwd)` call (keep
5577
- `generate_devin_hooks`). Update the `profile=full` dry-run message to drop
5578
- `.windsurf/hooks.json (Cascade, deprecated)`.
5579
- 3. **Tests:** remove the windsurf-`.windsurf/hooks.json` cases from
5580
- `tests/test_hooks_per_editor.bats` (output path, valid JSON, source tag,
5581
- `$HOME` prefix, idempotence, user-preservation, `pre_write_code` coverage) and
5582
- the `profile=full` assertion in `tests/test_install_profiles.bats`
5583
- (`windsurf + full emits .windsurf/hooks.json`). Keep all `.devin/hooks.v1.json`
5584
- tests. Adjust the README test-count badge to the new total.
5585
- 4. **Registry:** in `scripts/ecosystem_tools.json` (windsurf entry), remove
5586
- `scripts/generate_windsurf_hooks.py` from `our_generators`; keep
5587
- `.windsurf/hooks.json` out of `config_paths` (it was never listed). Trim the
5588
- `status_note` hooks-migration paragraph to past tense ("Cascade hooks removed
5589
- in vX.Y.Z").
5590
- 5. **Docs:** in `kb/reference/supported-tools-registry.md` drop the
5591
- `generate_windsurf_hooks.py` row and the "drop after 2026-07-01" note; in
5592
- `kb/reference/hooks-catalog.md` remove the Cascade row from the
5593
- Per-Editor Native Hooks table and the deprecation wording, leaving the Devin CLI
5594
- section as the windsurf-family hook surface.
5595
- 6. **validate.py:** the `_HOOK_STEM_ALIAS = {"devin": "windsurf"}` mapping STAYS —
5596
- it is what keeps the `devin` hook generator counted as windsurf hooks in the
5597
- README-honesty check after the Cascade generator is gone.
5598
- 7. **CHANGELOG / version:** minor bump, `Removed` entry, regen artifacts, full
5599
- release-preparation SOP gate.
5600
-
5601
- ## Verification
5602
-
5603
- - `python3 scripts/validate.py --strict` — 0/0 (editor-hooks-honesty must still
5604
- report windsurf as hook-enabled via the `devin` generator alias).
5605
- - `python3 scripts/ecosystem_doctor.py --offline --check` — exit 0.
5606
- - `npm test` — 0 `not ok`; no test recreates the deleted
5607
- `generate_windsurf_hooks.py` generator.
5608
- - `grep -rn "generate_windsurf_hooks" scripts/ tests/` returns nothing
5609
- (Art. VI.1 orphan check — the deleted generator is fully unwired).
5610
- `.windsurf/hooks.json` intentionally remains referenced by the one-time
5611
- migration/strip cleanup (`scripts/install_steps/ai_tools.py`) and its test,
5612
- and in narrative docs (CHANGELOG, README, `kb/`, docstrings).
5613
-
5614
- ## Do NOT touch
5615
-
5616
- - `generate_devin_hooks.py` and `.devin/hooks.v1.json` — the live replacement.
5617
- - The `.devin/`/`.windsurf/` rules + skills dual-emit (that fallback persists as
5618
- long as Devin Desktop reads legacy `.windsurf/` paths; this plan is hooks-only).
5619
-
5620
- ## Related
5621
-
5622
- - `kb/reference/hooks-catalog.md` — Per-Editor Native Hooks + Devin CLI section
5623
- - `kb/reference/supported-tools-registry.md` — windsurf entry, hooks-migration row
5624
- - `kb/procedures/ecosystem-sync-sop.md` — class-D deprecation workflow
5625
- - `scripts/ecosystem_tools.json` — windsurf `status_note`
5626
-
5627
- ---
5628
-
5629
- ## kb/planning/mcp-context-trim-v4-prd.md
5630
-
5631
- ---
5632
- title: "PRD: MCP Context Trim v4.0 — Local Proxy with Description Compression"
5633
- category: planning
5634
- service: ai-toolkit
5635
- tags:
5636
- - mcp
5637
- - proxy
5638
- - tool-descriptions
5639
- - jsonrpc
5640
- - tokens
5641
- - v4
5642
- doc_type: plan
5643
- status: proposed
5644
- created: "2026-05-04"
5645
- last_updated: "2026-05-04"
5646
- completion: "0%"
5647
- target_milestone: "v4.0"
5648
- predecessor:
5649
- - "kb/history/completed/output-token-discipline-plan-20260504.md"
5650
- - "kb/history/completed/f2-mcp-trim-spike-20260504.md"
5651
- description: "Local MCP proxy server that compresses tool descriptions before they reach the model. Carved out of the v3.2.0 output-token-discipline plan (Feature 2), deferred after the 2026-05-04 spike showed Claude Code hooks cannot modify tools/list metadata. Targets ~8-15k token reduction per session for users with many MCP servers."
5652
- ---
5653
-
5654
- # PRD: MCP Context Trim v4.0
5655
-
5656
- **Status:** Proposed
5657
- **Target milestone:** v4.0
5658
- **Carved out of:** [`output-token-discipline-plan-20260504.md`](../history/completed/output-token-discipline-plan-20260504.md) (was Feature 2)
5659
- **Spike basis:** [`f2-mcp-trim-spike-20260504.md`](../history/completed/f2-mcp-trim-spike-20260504.md)
5660
-
5661
- ## Problem
5662
-
5663
- MCP server tool descriptions are injected into every model turn's system prompt. With ~100 tools across 7 typical servers, descriptions consume 8–15k tokens per turn — pure overhead, paid every message. Examples observed in users' configs:
5664
-
5665
- - `dart-mcp-server` — ~30 tools with multi-paragraph descriptions
5666
- - `filesystem` — verbose paths and example sections
5667
- - `pencil` — "IMPORTANT" stanzas repeated across tools
5668
- - `jira-mcp` — long `Use this tool to…` boilerplate
5669
-
5670
- The v3.2.0 output-discipline plan attempted to solve this with a hook-based trimmer. The spike conducted 2026-05-04 proved Claude Code hooks do not expose `tools/list` metadata or the system-prompt tool catalog. The only viable architecture is a local MCP proxy.
5671
-
5672
- ## Goal
5673
-
5674
- Reduce MCP-description overhead by ≥40% per server, with **zero** loss of parameter schemas, required fields, or discrimination signals (`not`, `never`, `only`, `except`, `unless`).
5675
-
5676
- ## Non-goals
5677
-
5678
- - Modifying tool **call** behavior (only descriptions)
5679
- - Compressing user-facing prompts or completions
5680
- - Replacing or rewriting upstream MCP servers
5681
- - Touching MCP servers we do not control
5682
-
5683
- ## Architecture
5684
-
5685
- ### Proxy topology
5686
-
5687
- ```
5688
- Claude Code ──stdio──▶ ai-toolkit MCP proxy ──stdio/SSE──▶ upstream MCP server
5689
-
5690
- └─ rewrites tools/list response
5691
- passes through tools/call unchanged
5692
- ```
5693
-
5694
- One proxy process per upstream server, supervised by `ai-toolkit mcp-trim daemon` (or equivalent). User's `~/.claude/.mcp.json` is rewritten by `ai-toolkit install` (opt-in) to point Claude Code at the proxy instead of upstream — proxy reads the original target from a sidecar config.
5695
-
5696
- ### Required components
5697
-
5698
- | Component | Purpose |
5699
- |-----------|---------|
5700
- | `scripts/mcp_proxy_server.py` | JSON-RPC 2.0 proxy. Reads stdin, forwards to upstream over stdio or SSE, intercepts `tools/list` response, rewrites descriptions. Stdlib-only. |
5701
- | `scripts/mcp_description_trimmer.py` | Pure function library: `trim(description: str) → str`. Reused from heuristics below. Stdlib-only. |
5702
- | `scripts/mcp_proxy_config.py` | Reads `~/.softspark/ai-toolkit/mcp-proxy/servers.json`, validates upstream targets, generates supervisord/launchd config. |
5703
- | `app/hooks/mcp-proxy-health.sh` | SessionStart hook — verifies all configured proxies responsive; fall through (warn, do not block) if any down. |
5704
- | `app/skills/mcp-trim/SKILL.md` | Knowledge skill: how to enable, opt out, audit savings. |
5705
- | `bin/ai-toolkit-mcp-trim` | CLI: `enable`, `disable`, `status`, `audit` (per-server token savings report). |
5706
- | `tests/test_mcp_proxy.bats` | Integration tests with mock upstream MCP servers. |
5707
- | `tests/test_mcp_trimmer.bats` | Unit tests for description trim heuristics on captured fixtures. |
5708
-
5709
- ### Compression heuristics (from spike)
5710
-
5711
- Applied to each tool description in `tools/list` response:
6175
+ 6. **SARIF adoption low** — Users may not know how to use SARIF with GitHub. Mitigation: provide copy-paste GitHub Actions workflow in docs and `--explain` for onboarding.
5712
6176
 
5713
- - Drop example sections >40 chars
5714
- - Collapse `Use this server to…` / `Use this tool to…` boilerplate to minimum form preserving intent
5715
- - Drop duplicate occurrences of tool name in its own description
5716
- - **Preserve bytewise:** `inputSchema.properties[*].description`, `required`, `enum` values, URL/path identifiers
5717
- - **Never strip:** the words `not`, `never`, `only`, `except`, `unless` — these carry "when NOT to use" signals
5718
- - Target: ≥40% length reduction, 0% schema loss
6177
+ ---
5719
6178
 
5720
- ### Failure modes & rollback
6179
+ ## 12. Council Review Summary (2026-04-10)
5721
6180
 
5722
- | Scenario | Behavior |
5723
- |----------|----------|
5724
- | Proxy crashes mid-session | `mcp-proxy-health.sh` detects on next SessionStart, prints warning, suggests `ai-toolkit mcp-trim disable <server>` |
5725
- | Upstream MCP server changes its tool catalog | Proxy passes through unchanged tools (no cached schema), warns once if a tool's description was previously trimmed |
5726
- | Trimmer produces malformed JSON | Proxy falls through to upstream response unchanged, logs to `~/.softspark/ai-toolkit/mcp-proxy/error.log` |
5727
- | User wants to bypass | `AI_TOOLKIT_MCP_TRIM_DISABLE=1` env var → proxies pass everything through unchanged |
5728
- | User wants to fully uninstall | `ai-toolkit mcp-trim disable` reverts `~/.claude/.mcp.json` to original upstream targets |
6181
+ **Verdict:** CONDITIONAL FOR implement with scope reduction.
6182
+ **Confidence:** MEDIUM (weighted score: FOR 3.1 vs AGAINST 2.9)
5729
6183
 
5730
- ### Migration of existing user `.mcp.json`
6184
+ **Key insights applied to this plan:**
6185
+ - [x] Timeline revised from 3-4 → 5-6 weeks
6186
+ - [x] ~~Azure deferred to Milestone 3~~ → **reinstated: full 3-provider delivery**
6187
+ - [x] SARIF v2.1.0 output added — essential for GitHub Advanced Security integration
6188
+ - [x] Incremental scan mode added (`--changed`) — how developers actually use security tools
6189
+ - [x] `terraform show -json` wrapper instead of HCL parsing — realistic path
6190
+ - [x] Single config file `.cloud-security.json` (merged ignore + context)
6191
+ - [x] `credentials init` interactive wizard — reduce onboarding friction
6192
+ - [x] `--explain <rule-id>` for on-demand remediation guidance
6193
+ - [x] Static mode as default — zero-setup first experience
5731
6194
 
5732
- `ai-toolkit mcp-trim enable` does:
6195
+ **Deferred to v2:**
6196
+ - Kubernetes/container security (separate pack candidate)
6197
+ - Secret scanning with entropy detection
6198
+ - Compliance framework mapping (SOC2, PCI-DSS, NIST 800-53)
6199
+ - Visual security dashboard in browser
6200
+ - GitHub PR comment integration beyond SARIF
6201
+ - Vendored YAML subset parser for CloudFormation YAML static scanning
5733
6202
 
5734
- 1. Backup `~/.claude/.mcp.json` `~/.softspark/ai-toolkit/mcp-proxy/.mcp.json.bak.<timestamp>`
5735
- 2. Read each server entry, store in `~/.softspark/ai-toolkit/mcp-proxy/servers.json`
5736
- 3. Rewrite each entry to point at the local proxy (with sidecar `target` field)
5737
- 4. Spawn supervisor (per-OS: launchd on macOS, systemd on Linux, scheduled task on Windows)
5738
- 5. Verify each upstream reachable via proxy, abort + restore backup on any failure
6203
+ **Council strongest agreement:** False positive resolver is the killer feature and primary differentiator vs Checkov/Trivy/Prowler. No existing tool combines deterministic scanning with context-aware resolution.
5739
6204
 
5740
- ## Out-of-scope decisions (rejected mid-spike)
6205
+ ---
5741
6206
 
5742
- | Option | Why rejected |
5743
- |--------|--------------|
5744
- | Pre-install rewrite of `.mcp.json` only | MCP spec sources descriptions from server runtime, not config — wouldn't take effect |
5745
- | Source-side forks of MCP servers | Doesn't help users with custom servers; high maintenance |
5746
- | F2-lite observability tool | User decision 2026-05-04: tracking token waste without trimming is half-value; do the full thing in v4.0 |
5747
- | Hook-based interception | Spike proved hooks cannot reach `tools/list` |
6207
+ ## 13. Orchestration Review Summary (2026-04-10)
5748
6208
 
5749
- ## Success criteria
6209
+ **Agents:** tech-lead, security-architect, product-manager, code-reviewer (4 parallel)
5750
6210
 
5751
- - ≥40% description-length reduction per server on the captured fixture set (jira, filesystem, dart, pencil)
5752
- - Deep-equal `inputSchema` between trimmed and upstream — zero schema regression
5753
- - Proxy adds <50ms per `tools/list` call (one-time per session)
5754
- - Proxy adds <5ms per `tools/call` (passthrough overhead)
5755
- - Round-trip correctness: every tool callable via proxy returns byte-identical result vs direct call
5756
- - Zero MCP-skill regressions in `npm test` after enabling proxy in CI
5757
- - Rollback (`ai-toolkit mcp-trim disable`) restores byte-identical original `.mcp.json`
6211
+ **Verdict:** Plan structurally complete (14/14 elements). Three P0 security blockers identified and resolved.
5758
6212
 
5759
- ## Open questions
6213
+ **Applied changes:**
5760
6214
 
5761
- 1. Process supervision per-OS launchd / systemd / scheduled-task wrappers, or a built-in `ai-toolkit-mcp-trimd` daemon binary?
5762
- 2. SSE-mode upstreams (e.g., rag-mcp at `http://localhost:8081/mcp/sse`) — proxy listens on SSE locally too, or stdio-only with internal SSE client?
5763
- 3. Description rewrites static dictionary of "boilerplate phrases to drop" (faster, deterministic) vs LLM-based summarizer (more aggressive, less predictable)? Recommend static for v4.0, LLM as v4.1 stretch.
5764
- 4. Config path `~/.softspark/ai-toolkit/mcp-proxy/` (matches existing convention) or `~/.claude/mcp-proxy/` (closer to MCP config)? Recommend the former.
5765
- 5. Telemetry does this become an opt-in metric in `/briefing --tokens` ("MCP descriptions: 12.3k 7.2k, saved 5.1k per turn")? Recommend yes.
6215
+ | # | Action | Source | Priority | Applied? |
6216
+ |---|--------|--------|----------|----------|
6217
+ | 1 | Programmatic Bash allowlist | security-architect | P0 | Yes allowlist.sh + agent integration |
6218
+ | 2 | CI hardening (mktemp/trap/SARIF validation) | security-architect | P0 | Yes CI examples rewritten |
6219
+ | 3 | Suppression governance (justification + diff detection) | security-architect | P0 | Yes schema + SUPPRESSION_CHANGED finding |
6220
+ | 4 | Recursive descent parser for Firestore | code-reviewer | P1 | Yes — replaced regex approach, +1d estimate |
6221
+ | 5 | SARIF `driver.rules[]` for GitHub annotations | code-reviewer | P1 | Yes — schema + success criteria |
6222
+ | 6 | Task 4.1→3.2 numbering fix | tech-lead | P1 | Yes — renumbered |
6223
+ | 7 | `terraform plan` execution risk documented | security-architect | P1 | Yes — only `show -json` allowed |
6224
+ | 8 | `credentials init` deferred to M2 | code-reviewer | P2 | Yes — saves 1.5d in M1 |
6225
+ | 9 | False positive resolver budgeted +2d/provider | code-reviewer | P2 | Yes — estimate updated |
6226
+ | 10 | `SUPPRESSION_CHANGED` finding type | security-architect | P2 | Yes — in governance section |
5766
6227
 
5767
- ## Pre-mortem (failure scenarios to design against)
6228
+ **Market positioning (product-manager):**
6229
+ - Not competing with Checkov on check count (40 vs 3000)
6230
+ - Competing on: zero-noise (false positive resolver), zero-setup (static-first), IDE-native (10 platforms), AI interpretation
6231
+ - Target: developers in ai-toolkit ecosystem, not enterprise security teams
6232
+ - Value as ecosystem feature, not standalone product
5768
6233
 
5769
- 1. **Proxy gets out of sync with upstream** — upstream adds a new tool, proxy doesn't know how to compress it → passthrough that tool's description unchanged, log warning
5770
- 2. **Compression breaks tool discriminability** model picks wrong tool because trimmed description lost the "use only when X" qualifier → the `not/never/only/except/unless` blacklist must be exhaustive; add per-server allowlists for false positives
5771
- 3. **Multi-process race on `.mcp.json` rewrite** — two `ai-toolkit install` invocations clobber each other → file lock during enable/disable
5772
- 4. **Proxy supervisor fails to start on user's machine** different distro / no systemd → ai-toolkit doctor must detect and report; degrade to "MCP proxy unavailable, falling through" with no functionality loss
5773
- 5. **User has custom MCP server we don't recognize** — must work without per-server schema; default heuristics must be safe enough for arbitrary servers
6234
+ **Timeline revision (code-reviewer):**
6235
+ - 1 person: 6-7 weeks realistic (was 5-6)
6236
+ - 2 people: 4-5 weeks (parallel GCP + AWS tracks)
6237
+ - All 3 providers ship in 6 weeks — no conditional gates
5774
6238
 
5775
- ## Estimate
6239
+ ---
5776
6240
 
5777
- - Architecture spike + working proxy prototype: 2 days
5778
- - Production proxy + supervisor + config + CLI: 3 days
5779
- - Test suite + fixtures + CI integration: 2 days
5780
- - Documentation + migration guide + release notes: 1 day
6241
+ ## 14. Next Actions
5781
6242
 
5782
- **Total: ~8 working days** (1.5–2 weeks calendar time at typical pace)
6243
+ 1. [ ] Approve plan
6244
+ 2. [ ] Implement `credentials` CLI command (1.1) + Bash allowlist
6245
+ 3. [ ] Create `cloud-security-auditor` agent (1.2)
6246
+ 4. [ ] Implement SARIF formatter + incremental scan (1.3)
6247
+ 5. [ ] Implement `firebase-rules-audit` — recursive descent parser (2.1)
6248
+ 6. [ ] Implement `cloud-functions-audit` + false positive resolver GCP (2.2, 2.3)
6249
+ 7. [ ] Implement `aws-security-audit` + `terraform show -json` wrapper (3.1)
6250
+ 8. [ ] Implement orchestrator + plugin pack + `credentials init` (3.2, 1.1b)
6251
+ 9. [ ] Implement `azure-security-audit` + false positive resolver Azure (4.1)
6252
+ 10. [ ] Full test suite (70+) + documentation + release
5783
6253
 
5784
- ## Status
6254
+ ---
5785
6255
 
5786
- | Date | Status | Author |
5787
- |------|--------|--------|
5788
- | 2026-05-04 | PRD drafted from spike conclusions, carved out of v3.2.0 plan | claude |
6256
+ **Last Updated:** 2026-04-10
6257
+ **Council Reviewed:** 2026-04-10
6258
+ **Orchestration Reviewed:** 2026-04-10 (4 agents: tech-lead, security-architect, product-manager, code-reviewer)
5789
6259
 
5790
6260
  ---
5791
6261
 
@@ -6770,10 +7240,10 @@ title: "SOP: Release Preparation"
6770
7240
  category: procedures
6771
7241
  service: ai-toolkit
6772
7242
  tags: [sop, release, version, publish, changelog, semver, provenance, sarif, ecosystem, shellcheck]
6773
- version: "1.11.2"
7243
+ version: "1.13.0"
6774
7244
  created: "2026-04-10"
6775
7245
  last_updated: "2026-07-27"
6776
- description: "Step-by-step checklist for preparing a new ai-toolkit release — ecosystem-sync drift check, version sync, changelog, artifact regeneration, validation, and tagging. Run BEFORE every git tag. Includes mandatory Provenance, SARIF, and checksum-pin checks added in v2.8.0, the single-run npm test discipline added in v1.8.0, the ecosystem-sync gate added in v1.9.0, the registry-vs-generators drift gate added in v1.10.0, and the mandatory pre-tag ShellCheck gate added in v1.11.0 (publish.yml does not run ShellCheck, so a hook lint failure can publish while reddening main CI — see the v4.5.1 postmortem in Phase 5)."
7246
+ description: "Step-by-step checklist for preparing a new ai-toolkit release — ecosystem-sync drift check, version sync, changelog, artifact regeneration, validation, and tagging. Run BEFORE every git tag. Includes mandatory Provenance, SARIF, and checksum-pin checks added in v2.8.0, the single-run npm test discipline added in v1.8.0, the ecosystem-sync gate added in v1.9.0, the registry-vs-generators drift gate added in v1.10.0, the mandatory pre-tag ShellCheck gate added in v1.11.0 (publish.yml does not run ShellCheck, so a hook lint failure can publish while reddening main CI — see the v4.5.1 postmortem in Phase 5), the pre-push tag assertions added in v1.12.0 after v4.19.0 was tagged on the wrong commit (Phase 7), and the licensing gate added in v1.13.0 with the move to Apache-2.0 (Phase 5c)."
6777
7247
  ---
6778
7248
 
6779
7249
  # SOP: Release Preparation
@@ -6832,10 +7302,20 @@ python3 scripts/audit_skills.py --permissions # review Bash/Write/Edit footpri
6832
7302
  # 5b. Ecosystem gate — snapshot must be current before tag
6833
7303
  python3 scripts/ecosystem_doctor.py --offline --check || { echo "STALE ecosystem snapshot — re-run doctor"; exit 1; }
6834
7304
 
7305
+ # 5c. Licensing gate — SPDX headers, LICENSE, NOTICE, manifest consistency
7306
+ npx bats tests/test_licensing.bats || { echo "LICENSING GATE FAILED"; exit 1; }
7307
+
6835
7308
  # 6. Commit + tag + push
6836
7309
  git add -A && git commit -m "chore: release vX.Y.Z"
6837
7310
  git tag vX.Y.Z
6838
- git push origin main --tags
7311
+
7312
+ # 6a. Assert the tag before pushing it (v4.19.0 postmortem, Phase 7)
7313
+ test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" || { echo "FAIL: tag not on HEAD"; exit 1; }
7314
+ git show --no-patch --format=%s vX.Y.Z | grep -qx "chore: release vX.Y.Z" || { echo "FAIL: tag not on release commit"; exit 1; }
7315
+
7316
+ # 6b. Branch first, then the single tag by full ref. Never --tags.
7317
+ git push origin main
7318
+ git push origin refs/tags/vX.Y.Z
6839
7319
  ```
6840
7320
 
6841
7321
  ---
@@ -7099,6 +7579,46 @@ python3 scripts/validate.py --strict && python3 scripts/audit_skills.py --ci &&
7099
7579
  - Missing frontmatter → add to new KB docs
7100
7580
  - Broken symlink → `ai-toolkit doctor --fix`
7101
7581
 
7582
+ ### Phase 5c: Licensing Gate (v4.20.0+)
7583
+
7584
+ The project is Apache-2.0. Attribution only works if the artefact actually
7585
+ carries it, and every part of that is mechanically checkable.
7586
+
7587
+ ```bash
7588
+ # The whole gate, enforced in CI. Run it here so a failure is caught before tagging.
7589
+ npx bats tests/test_licensing.bats
7590
+ ```
7591
+
7592
+ The seven assertions, and why each exists:
7593
+
7594
+ | Check | Fails when |
7595
+ |---|---|
7596
+ | Every shipped source file carries an SPDX header | A new `.py`/`.sh`/`.js`/`.bats` file was added without one — the common case, and the reason this is a test rather than a habit |
7597
+ | Headers name Apache-2.0 and nothing else | A file was copied in from an MIT/GPL source with its own header intact |
7598
+ | **No** markdown file carries an SPDX header | Someone "helpfully" ran the header script over `app/skills/` — headers there sit above parsed frontmatter and bill every session for it |
7599
+ | `LICENSE` is the complete Apache 2.0 text | The file was truncated or replaced with a summary |
7600
+ | `NOTICE` carries attribution, the source URL, §4(d) and the MIT-era notice | The attribution mechanism was gutted |
7601
+ | `LICENSE` **and** `NOTICE` ship in the npm package | `package.json` `files` lost an entry — a NOTICE that never reaches the consumer cannot satisfy §4(d) |
7602
+ | Every manifest declaring a licence declares Apache-2.0 | `package.json`, `manifest.json`, `plugin.json` and `package-lock.json` drifted apart |
7603
+
7604
+ **Adding source files in this release?** The header goes *after* the shebang,
7605
+ never before it. Short SPDX form:
7606
+
7607
+ ```
7608
+ # SPDX-License-Identifier: Apache-2.0
7609
+ # Copyright 2024-2026 Lukasz Krzemien (biuro@softspark.eu)
7610
+ # Source: https://github.com/softspark/ai-toolkit
7611
+ ```
7612
+
7613
+ `//` for JavaScript. Full convention and the reasoning behind the markdown
7614
+ exclusion: [Licensing](../reference/licensing.md).
7615
+
7616
+ **Changing the licence itself?** Do not hand-type the licence text. Take it
7617
+ verbatim from a published copy and cross-verify against a second independent
7618
+ copy before writing `LICENSE` — a rendered or summarised licence is not the
7619
+ licence. Prior releases stay under their original terms; a licence change
7620
+ applies going forward and revokes nothing already granted.
7621
+
7102
7622
  ### Phase 5a: Supply-Chain Hardening Verification (v2.8.0+)
7103
7623
 
7104
7624
  These checks enforce the security standard introduced in v2.8.0. Do NOT tag a release until all pass.
@@ -7172,8 +7692,33 @@ git commit -m "chore: release vX.Y.Z"
7172
7692
 
7173
7693
  ```bash
7174
7694
  git tag vX.Y.Z
7175
- git push origin main --tags
7176
- ```
7695
+
7696
+ # Assert the tag before pushing it. Both checks are one line each and both
7697
+ # have caught a real broken release.
7698
+ test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" \
7699
+ || { echo "FAIL: tag is not on HEAD"; exit 1; }
7700
+ git show --no-patch --format=%s vX.Y.Z | grep -qx "chore: release vX.Y.Z" \
7701
+ || { echo "FAIL: tag is not on the chore: release commit"; exit 1; }
7702
+
7703
+ # Push the branch, then the single release tag by its full ref.
7704
+ git push origin main
7705
+ git push origin refs/tags/vX.Y.Z
7706
+ ```
7707
+
7708
+ **Why the assertions (v4.19.0 postmortem).** v4.19.0 was tagged on a commit
7709
+ that contained only a KB document and still carried `package.json` version
7710
+ `4.18.0`; the actual release sat in the commit above it under a recycled
7711
+ `fix:` message. `publish.yml` fired, tried to publish a version already on
7712
+ npm, and failed. Nothing on npm, a tag pointing at the wrong tree, and the
7713
+ only way out was rewriting a pushed commit. Both assertions above catch this
7714
+ in under a second. Run them.
7715
+
7716
+ **Never `git push --tags`.** It pushes every local tag at once, and GitHub
7717
+ suppresses tag-triggered workflow runs when many tags arrive in a single push
7718
+ — the workflow silently does not fire and nothing publishes. Push the single
7719
+ release tag by its full ref, as above. (Sibling evidence: this is exactly how
7720
+ rag-mcp's `1.0.3` image build was skipped, when a `--tags` push carried 37
7721
+ tags at once.)
7177
7722
 
7178
7723
  This triggers `.github/workflows/publish.yml` which:
7179
7724
  1. Runs `validate.py --strict`
@@ -7227,10 +7772,13 @@ git push origin --delete vX.Y.Z
7227
7772
  | 13 | ShellCheck hooks | `shellcheck --severity=warning app/hooks/*.sh` | Exit 0, no output (mirrors ci.yml; publish.yml does NOT run it) |
7228
7773
  | 14 | Provenance flag check | `grep -- '--provenance' .github/workflows/publish.yml` | Present |
7229
7774
  | 15 | Checksum-pin backfill | `sources.json` entries all have `sha256` | No unpinned URL sources |
7775
+ | 15a | Licensing gate | `npx bats tests/test_licensing.bats` | 7/7 — SPDX headers, LICENSE, NOTICE, npm `files`, manifest consistency |
7230
7776
  | 16 | Tests | `git add -A kb/` if the KB changed, then `npm test` | All pass |
7231
7777
  | 17 | Commit | `git commit` | Clean working tree |
7232
7778
  | 18 | Tag | `git tag vX.Y.Z` | Tag exists |
7233
- | 19 | Push | `git push origin main --tags` | CI triggered with `id-token: write` |
7779
+ | 18a | Tag is on HEAD | `test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)"` | Exit 0 |
7780
+ | 18b | Tag is on the release commit | `git show --no-patch --format=%s vX.Y.Z` | Reads `chore: release vX.Y.Z` |
7781
+ | 19 | Push branch, then the single tag | `git push origin main && git push origin refs/tags/vX.Y.Z` | CI triggered with `id-token: write`. Never `--tags`. |
7234
7782
 
7235
7783
  ---
7236
7784
 
@@ -9245,7 +9793,7 @@ description: "Feature comparison of ai-toolkit vs other Claude Code toolkits and
9245
9793
  | Session persistence | Yes | Yes | No | No |
9246
9794
  | Architecture notes | **Yes** | No | No | No |
9247
9795
  | KB/RAG integration | **Yes** | No | No | Yes |
9248
- | License | MIT | MIT | MIT | MIT |
9796
+ | License | **Apache-2.0** (NOTICE attribution, change notices, patent grant) | MIT | MIT | MIT |
9249
9797
 
9250
9798
  For live benchmark data, see the [ecosystem benchmark snapshot](claude-ecosystem-benchmark-snapshot.md).
9251
9799
 
@@ -10319,7 +10867,7 @@ Base configs can define non-overridable constraints via the `enforce` block:
10319
10867
  {
10320
10868
  "enforce": {
10321
10869
  "minHookProfile": "standard",
10322
- "requiredPlugins": ["security-pack"],
10870
+ "requiredPlugins": ["memory-pack"],
10323
10871
  "forbidOverride": ["constitution", "guard-destructive"],
10324
10872
  "requiredAgents": ["security-auditor"]
10325
10873
  }
@@ -12052,63 +12600,6 @@ ai-toolkit add-rule ./jira-rules.md
12052
12600
 
12053
12601
  ---
12054
12602
 
12055
- ## kb/reference/language-packs.md
12056
-
12057
- ---
12058
- title: "AI Toolkit - Language Plugin Packs"
12059
- category: reference
12060
- service: ai-toolkit
12061
- tags: [plugins, languages, rust, java, csharp, kotlin, swift, ruby]
12062
- version: "1.0.0"
12063
- created: "2026-03-29"
12064
- last_updated: "2026-03-29"
12065
- description: "6 language-specific plugin packs providing knowledge skills for Rust, Java, C#, Kotlin, Swift, and Ruby."
12066
- ---
12067
-
12068
- # Language Plugin Packs
12069
-
12070
- ## Overview
12071
-
12072
- Language packs are domain-scoped plugin packs that provide knowledge skills for specific programming languages. Each pack contains a single knowledge skill with idiomatic patterns, error handling, testing conventions, common frameworks, and performance tips.
12073
-
12074
- ## Available Packs
12075
-
12076
- | Pack | Skill | Language | Key Topics |
12077
- |------|-------|----------|------------|
12078
- | `rust-pack` | `rust-patterns` | Rust | Ownership, borrowing, Cargo, tokio, serde |
12079
- | `java-pack` | `java-patterns` | Java | Records, sealed classes, Spring Boot, JUnit 5 |
12080
- | `csharp-pack` | `csharp-patterns` | C# / .NET | Nullable refs, async/await, ASP.NET Core, EF Core |
12081
- | `kotlin-pack` | `kotlin-patterns` | Kotlin | Coroutines, DSLs, sealed classes, Ktor, MockK |
12082
- | `swift-pack` | `swift-patterns` | Swift / iOS | Protocol-oriented, SwiftUI, async/await, SPM |
12083
- | `ruby-pack` | `ruby-patterns` | Ruby | Blocks, Rails conventions, RSpec, ActiveRecord |
12084
-
12085
- ## Skill Content Sections
12086
-
12087
- Each language skill follows a consistent structure:
12088
-
12089
- 1. **Project Structure** — standard directory layout and build tool configuration
12090
- 2. **Idioms / Code Style** — language-specific patterns and conventions
12091
- 3. **Error Handling** — error types, patterns, and best practices
12092
- 4. **Testing Patterns** — test frameworks, assertion libraries, mocking
12093
- 5. **Common Libraries / Frameworks** — ecosystem essentials
12094
- 6. **Performance Tips** — optimization techniques and profiling
12095
- 7. **Build / Package Management** — dependency management and CI
12096
-
12097
- ## How Knowledge Skills Work
12098
-
12099
- These skills have `user-invocable: false` in their frontmatter, meaning they are NOT slash commands. Instead, Claude loads them contextually when the conversation topic matches the skill's description trigger.
12100
-
12101
- For example, when a user asks "How do I handle errors in Rust?", Claude automatically loads `rust-patterns` to provide idiomatic Rust error handling guidance.
12102
-
12103
- ## Requesting New Language Packs
12104
-
12105
- File an issue with the `language-pack` label. Include:
12106
- - Language name
12107
- - Key topics to cover
12108
- - Popular frameworks/libraries to include
12109
-
12110
- ---
12111
-
12112
12603
  ## kb/reference/language-rules.md
12113
12604
 
12114
12605
  ---
@@ -12356,6 +12847,159 @@ Per-language content delivered as a knowledge skill is the same Markdown that ot
12356
12847
 
12357
12848
  ---
12358
12849
 
12850
+ ## kb/reference/licensing.md
12851
+
12852
+ ---
12853
+ title: "Licensing"
12854
+ category: reference
12855
+ service: ai-toolkit
12856
+ tags: [licence, apache-2.0, spdx, notice, attribution, headers, mit]
12857
+ version: "1.0.0"
12858
+ created: "2026-07-27"
12859
+ last_updated: "2026-07-27"
12860
+ description: "ai-toolkit is Apache-2.0 from v4.20.0. What that obliges a redistributor to do, why NOTICE is the point, the SPDX header convention and which files deliberately do not get one, how MIT-era contributions are handled, and the CI gate that enforces all of it."
12861
+ ---
12862
+
12863
+ # Licensing
12864
+
12865
+ ai-toolkit is licensed under the **Apache License 2.0** from v4.20.0. Releases up
12866
+ to and including v4.20.0 were published under MIT and remain available under MIT.
12867
+ The change applies going forward and revokes nothing already granted.
12868
+
12869
+ Canonical files: [`LICENSE`](../../LICENSE) (verbatim Apache-2.0 text) and
12870
+ [`NOTICE`](../../NOTICE) (attribution).
12871
+
12872
+ ## Why Apache-2.0, given MIT already required attribution
12873
+
12874
+ This is the part most often got wrong. MIT already says:
12875
+
12876
+ > The above copyright notice and this permission notice shall be included in all
12877
+ > copies or substantial portions of the Software.
12878
+
12879
+ So attribution was never the new thing. What Apache-2.0 adds:
12880
+
12881
+ | Mechanism | MIT | Apache-2.0 |
12882
+ |---|---|---|
12883
+ | Copyright notice must be preserved | yes | yes |
12884
+ | **`NOTICE` contents must travel into redistributions** (§4d) | — | **yes** |
12885
+ | **Modified files must carry a notice saying they changed** (§4b) | — | **yes** |
12886
+ | Express patent grant, terminated by patent litigation (§3) | — | yes |
12887
+ | No rights to the licensor's names or marks (§6) | — | yes |
12888
+
12889
+ **`NOTICE` is the reason for the change.** It is the only mechanism in a
12890
+ permissive licence that forces a redistributor to reproduce your attribution —
12891
+ project name, copyright, source URL — somewhere their users can see it. Without
12892
+ it, MIT and Apache-2.0 are close to equivalent in practice.
12893
+
12894
+ Consequence for packaging: `NOTICE` is listed in `package.json` `files`. A NOTICE
12895
+ that does not reach the consumer cannot satisfy §4(d), so that entry is a
12896
+ licensing requirement, not housekeeping, and is asserted in CI.
12897
+
12898
+ ## What a fork owes
12899
+
12900
+ Fork it, modify it, ship it commercially. Three obligations:
12901
+
12902
+ 1. **Carry the `NOTICE`** into your distribution (§4d).
12903
+ 2. **Say which files you changed** (§4b).
12904
+ 3. **Do not use the "ai-toolkit" or "SoftSpark" names or marks** as if endorsed (§6).
12905
+
12906
+ ## Source header convention
12907
+
12908
+ Short SPDX form, three lines, always **after** the shebang — an interpreter
12909
+ directive must stay on line 1 — and after a Python `coding:` line if present:
12910
+
12911
+ ```bash
12912
+ #!/usr/bin/env bash
12913
+ # SPDX-License-Identifier: Apache-2.0
12914
+ # Copyright 2024-2026 Lukasz Krzemien (biuro@softspark.eu)
12915
+ # Source: https://github.com/softspark/ai-toolkit
12916
+ #
12917
+ # guard-path.sh — the file's own description continues here.
12918
+ ```
12919
+
12920
+ `//` for JavaScript. SPDX was chosen over the 13-line Apache APPENDIX boilerplate
12921
+ because it is machine-readable — licence scanners, GitHub and SBOM tooling parse
12922
+ it — and because 13 lines on top of every source file buries the description that a
12923
+ reader of a hook actually needs.
12924
+
12925
+ ### Which files get a header
12926
+
12927
+ | Included | Count |
12928
+ |---|---:|
12929
+ | `scripts/**/*.py` | 109 |
12930
+ | `tests/*.bats` | 77 |
12931
+ | `app/hooks/*.sh` | 32 |
12932
+ | `app/skills/**/*.py`, `**/*.js` | 27 |
12933
+ | `app/plugins/**/*.sh`, `**/*.py` | 6 |
12934
+ | `bin/*.js`, `benchmarks/**/*.py` | 2 |
12935
+ | **total** | **253** |
12936
+
12937
+ These are a snapshot, not a contract — the CI gate checks that *every* matching
12938
+ file has a header, so the count moves with the codebase and nothing needs
12939
+ updating here when it does.
12940
+
12941
+ ### Which files deliberately do not, and why
12942
+
12943
+ **No markdown file carries a header.** Not `app/skills/*/SKILL.md`, not
12944
+ `app/agents/*.md`, not `app/rules/`, not `kb/`. Two reasons, both concrete:
12945
+
12946
+ 1. **Frontmatter.** Skill and agent files open with parsed YAML. A header above
12947
+ it breaks parsing; a header below it is invisible where it matters.
12948
+ 2. **Token cost.** Skill and agent descriptions load into the system prompt of
12949
+ every session — measured at 5,051 and 2,750 tokens respectively. A four-line
12950
+ header across 108 skills and 45 agents would be a permanent per-session cost,
12951
+ billed on every conversation forever, for a notice Apache only *recommends*.
12952
+ `LICENSE` and `NOTICE` carry the full terms; the headers are a convenience.
12953
+
12954
+ This exclusion is asserted in CI, so a well-meant sweep of the header script over
12955
+ `app/skills/` fails the build rather than silently taxing every session.
12956
+
12957
+ ## MIT-era contributions
12958
+
12959
+ Contributions made while the project was MIT-licensed remain the copyright of
12960
+ their authors and were received under MIT terms. Three contributors other than
12961
+ the maintainer appear in the history.
12962
+
12963
+ MIT explicitly permits sublicensing, so those contributions are redistributed
12964
+ here under Apache-2.0 **with the original MIT notice preserved verbatim** in
12965
+ `NOTICE`, which is what MIT requires. This is standard practice for an MIT to
12966
+ Apache-2.0 move and needs no contributor sign-off. A "clean" Apache-2.0 with no
12967
+ MIT remnant would need each contributor's agreement.
12968
+
12969
+ *This is a description of what the project does, not legal advice.*
12970
+
12971
+ ## Enforcement
12972
+
12973
+ `tests/test_licensing.bats`, seven assertions, run by `npm test` in CI:
12974
+
12975
+ - every shipped source file carries an SPDX header
12976
+ - headers name Apache-2.0 and nothing else
12977
+ - **no** markdown file carries a header
12978
+ - `LICENSE` is the complete Apache 2.0 text, appendix included
12979
+ - `NOTICE` carries attribution, the source URL, §4(d) and the MIT-era notice
12980
+ - `LICENSE` and `NOTICE` both appear in `package.json` `files`
12981
+ - every manifest declaring a licence declares Apache-2.0
12982
+
12983
+ It is a test rather than a checklist line on purpose. This project has two
12984
+ same-day postmortems about SOPs that existed and were skipped; CI does not skip.
12985
+ [Release Preparation](../procedures/release-preparation-sop.md) Phase 5c runs the
12986
+ same gate before tagging so a failure surfaces before the tag, not after.
12987
+
12988
+ ## If the licence ever changes again
12989
+
12990
+ Do not hand-type the licence text and do not paste a rendered copy — a
12991
+ markdown-formatted licence is not the licence. Take it verbatim from a published
12992
+ source, cross-verify against a second independent copy, and only then write
12993
+ `LICENSE`. That is how the Apache-2.0 text in this repository was installed.
12994
+
12995
+ ## Related
12996
+
12997
+ - [`LICENSE`](../../LICENSE), [`NOTICE`](../../NOTICE)
12998
+ - [Release Preparation SOP](../procedures/release-preparation-sop.md) — Phase 5c
12999
+ - [Distribution Model](distribution-model.md) — what ships and where
13000
+
13001
+ ---
13002
+
12359
13003
  ## kb/reference/manifest-install.md
12360
13004
 
12361
13005
  ---
@@ -13670,22 +14314,30 @@ ai-toolkit plugin status --editor all # show installed packs with r
13670
14314
 
13671
14315
  ## Current Experimental Packs
13672
14316
 
13673
- | Pack | Domain | Agents | Skills | Hooks | Description |
13674
- |------|--------|--------|--------|-------|-------------|
13675
- | `security-pack` | security | 3 | 3 | 2 | Security auditing, threat modeling, OWASP |
13676
- | `research-pack` | research | 4 | 4 | 1 | Multi-source research, synthesis, fact-checking |
13677
- | `frontend-pack` | frontend | 3 | 3 | 1 | React/Vue/CSS, SEO, design engineering |
13678
- | `enterprise-pack` | enterprise | 3 | 3 | 3 | Executive briefings, infra architecture, status |
13679
- | `memory-pack` | memory | 0 | 1 | 2 | SQLite persistent memory with FTS5 search |
13680
- | `rust-pack` | rust | 0 | 1 | 0 | Rust patterns |
13681
- | `java-pack` | java | 0 | 1 | 0 | Java patterns |
13682
- | `csharp-pack` | csharp | 0 | 1 | 0 | C# patterns |
13683
- | `kotlin-pack` | kotlin | 0 | 1 | 0 | Kotlin patterns |
13684
- | `swift-pack` | swift | 0 | 1 | 0 | Swift patterns |
13685
- | `ruby-pack` | ruby | 0 | 1 | 0 | Ruby patterns |
13686
-
13687
- Every pack here is content that ships in this repository. None fetches anything
13688
- at install time.
14317
+ | Pack | Domain | Owns | Installs (claude / codex) | Description |
14318
+ |------|--------|------|---------------------------|-------------|
14319
+ | `memory-pack` | memory | 2 hooks, 2 scripts, 1 skill | 4 / 4 files | SQLite persistent memory with FTS5 search |
14320
+ | `enterprise-pack` | enterprise | 2 hooks | 2 / 2 files | Status-line and output-style overlays |
14321
+
14322
+ Both packs ship content in this repository. Neither fetches anything at install
14323
+ time.
14324
+
14325
+ ### The rule the table now enforces
14326
+
14327
+ **A pack must install files the core install does not.** `ai-toolkit install`
14328
+ links every core skill and agent, so a manifest naming only core assets resolves
14329
+ to nothing: `plugin install` reports `(0 file items)` and no file appears on
14330
+ disk. This is not a subtle degradation — it is a complete no-op, identical on
14331
+ every profile (`minimal`, `standard`, `strict`) and on both runtimes.
14332
+
14333
+ Nine packs were removed in v4.20.0 for failing this: `csharp`, `java`, `kotlin`,
14334
+ `ruby`, `rust`, `swift`, `frontend`, `research`, `security`. Every one declared
14335
+ only skills and agents that already ship in core, and eight of them owned nothing
14336
+ but a `README.md`. Full measurement:
14337
+ [`no-op-plugin-packs-removed-20260727.md`](../history/completed/no-op-plugin-packs-removed-20260727.md).
14338
+
14339
+ Before adding a pack, prove it does something: install core into a throwaway
14340
+ `HOME`, install the pack, and check that the reported file count is above zero.
13689
14341
 
13690
14342
  **A pack that downloads a binary has been tried once and retired.** `rtk-pack`
13691
14343
  (v4.18.0, removed in v4.19.0) fetched a checksum-pinned artifact in