@softspark/ai-toolkit 4.19.1 → 4.21.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 (217) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +201 -21
  3. package/NOTICE +55 -0
  4. package/README.md +35 -21
  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/documentation-standards/SKILL.md +25 -5
  58. package/app/skills/explain/scripts/dependency-graph.py +4 -0
  59. package/app/skills/explore/scripts/visualize.py +4 -0
  60. package/app/skills/fix/scripts/error-classifier.py +4 -0
  61. package/app/skills/health/scripts/health_check.py +4 -0
  62. package/app/skills/hipaa-validate/scripts/hipaa_scan.py +4 -0
  63. package/app/skills/lint/scripts/detect-linters.py +4 -0
  64. package/app/skills/migrate/scripts/migration-status.py +4 -0
  65. package/app/skills/plugin-creator/SKILL.md +18 -8
  66. package/app/skills/pr/scripts/pr-summary.py +4 -0
  67. package/app/skills/refactor/scripts/refactor-scan.py +4 -0
  68. package/app/skills/review/scripts/diff-analyzer.py +4 -0
  69. package/app/skills/rollback/scripts/rollback_info.py +4 -0
  70. package/app/skills/seo-validate/scripts/seo-scanner.py +4 -0
  71. package/app/skills/skill-creator/templates/reasoning-engine/search.py +4 -0
  72. package/app/skills/test/scripts/detect-runner.py +4 -0
  73. package/app/skills/write-a-prd/scripts/poll.js +4 -0
  74. package/benchmarks/ecosystem-doctor-snapshot.json +3 -3
  75. package/benchmarks/run.py +4 -0
  76. package/bin/ai-toolkit.js +4 -0
  77. package/kb/{planning/drop-cascade-hooks-after-sunset.md → history/completed/drop-cascade-hooks-after-sunset-20260710.md} +24 -0
  78. package/kb/{reference/language-packs.md → history/completed/language-packs-removed-20260727.md} +32 -7
  79. package/kb/{planning/mcp-context-trim-v4-prd.md → history/completed/mcp-context-trim-v4-prd-obsoleted-20260727.md} +43 -9
  80. package/kb/history/completed/no-op-plugin-packs-removed-20260727.md +127 -0
  81. package/kb/history/completed/tool-output-token-reduction-closed-20260727.md +190 -0
  82. package/kb/procedures/release-preparation-sop.md +83 -5
  83. package/kb/reference/comparison.md +1 -1
  84. package/kb/reference/enterprise-config-guide.md +1 -1
  85. package/kb/reference/licensing.md +148 -0
  86. package/kb/reference/plugin-pack-conventions.md +24 -16
  87. package/llms-full.txt +1182 -530
  88. package/llms.txt +6 -3
  89. package/manifest.json +1 -1
  90. package/package.json +3 -2
  91. package/scripts/_common.py +4 -0
  92. package/scripts/add_rule.py +4 -0
  93. package/scripts/audit_skills.py +4 -0
  94. package/scripts/benchmark_config.py +4 -0
  95. package/scripts/benchmark_ecosystem.py +4 -0
  96. package/scripts/check_deps.py +4 -0
  97. package/scripts/claude_app.py +4 -0
  98. package/scripts/codex_skill_adapter.py +4 -0
  99. package/scripts/compile_slm.py +4 -0
  100. package/scripts/config_cli.py +4 -0
  101. package/scripts/config_lock.py +4 -0
  102. package/scripts/config_merger.py +4 -0
  103. package/scripts/config_resolver.py +4 -0
  104. package/scripts/config_scaffold.py +5 -1
  105. package/scripts/config_validator.py +4 -0
  106. package/scripts/create_skill.py +4 -0
  107. package/scripts/dir_rules_shared.py +4 -0
  108. package/scripts/doctor.py +4 -0
  109. package/scripts/ecosystem_doctor.py +4 -0
  110. package/scripts/eject.py +4 -0
  111. package/scripts/emission.py +4 -0
  112. package/scripts/evaluate_skills.py +4 -0
  113. package/scripts/frontmatter.py +4 -0
  114. package/scripts/generate_agents_md.py +4 -0
  115. package/scripts/generate_aider_conf.py +4 -0
  116. package/scripts/generate_antigravity.py +4 -0
  117. package/scripts/generate_augment.py +4 -0
  118. package/scripts/generate_augment_agents.py +4 -0
  119. package/scripts/generate_augment_commands.py +4 -0
  120. package/scripts/generate_augment_hooks.py +4 -0
  121. package/scripts/generate_augment_rules.py +4 -0
  122. package/scripts/generate_augment_skills.py +4 -0
  123. package/scripts/generate_cline.py +4 -0
  124. package/scripts/generate_cline_rules.py +4 -0
  125. package/scripts/generate_cline_skills.py +4 -0
  126. package/scripts/generate_codex.py +4 -0
  127. package/scripts/generate_codex_agents.py +4 -0
  128. package/scripts/generate_codex_hooks.py +4 -0
  129. package/scripts/generate_codex_skills.py +4 -0
  130. package/scripts/generate_conventions.py +4 -0
  131. package/scripts/generate_copilot.py +4 -0
  132. package/scripts/generate_copilot_hooks.py +4 -0
  133. package/scripts/generate_cursor_agents.py +4 -0
  134. package/scripts/generate_cursor_hooks.py +4 -0
  135. package/scripts/generate_cursor_mdc.py +4 -0
  136. package/scripts/generate_cursor_rules.py +4 -0
  137. package/scripts/generate_cursor_skills.py +4 -0
  138. package/scripts/generate_devin_hooks.py +4 -0
  139. package/scripts/generate_gemini.py +4 -0
  140. package/scripts/generate_gemini_commands.py +4 -0
  141. package/scripts/generate_gemini_hooks.py +4 -0
  142. package/scripts/generate_gemini_skills.py +4 -0
  143. package/scripts/generate_language_rules_skills.py +4 -0
  144. package/scripts/generate_llms_txt.py +4 -0
  145. package/scripts/generate_opencode.py +4 -0
  146. package/scripts/generate_opencode_agents.py +4 -0
  147. package/scripts/generate_opencode_commands.py +4 -0
  148. package/scripts/generate_opencode_json.py +4 -0
  149. package/scripts/generate_opencode_plugin.py +4 -0
  150. package/scripts/generate_roo_modes.py +4 -0
  151. package/scripts/generate_roo_rules.py +4 -0
  152. package/scripts/generate_windsurf.py +4 -0
  153. package/scripts/generate_windsurf_rules.py +4 -0
  154. package/scripts/generate_windsurf_skills.py +4 -0
  155. package/scripts/generator_base.py +4 -0
  156. package/scripts/harvest_ecosystem.py +4 -0
  157. package/scripts/hook_sources.py +4 -0
  158. package/scripts/inject_hook_cli.py +4 -0
  159. package/scripts/inject_mcp_cli.py +4 -0
  160. package/scripts/inject_rule_cli.py +4 -0
  161. package/scripts/inject_section_cli.py +4 -0
  162. package/scripts/injection.py +4 -0
  163. package/scripts/install.py +4 -0
  164. package/scripts/install_git_hooks.py +4 -0
  165. package/scripts/install_steps/__init__.py +4 -0
  166. package/scripts/install_steps/ai_tools.py +4 -0
  167. package/scripts/install_steps/detect_language.py +4 -0
  168. package/scripts/install_steps/hooks.py +4 -0
  169. package/scripts/install_steps/install_state.py +4 -0
  170. package/scripts/install_steps/markers.py +4 -0
  171. package/scripts/install_steps/project_registry.py +4 -0
  172. package/scripts/install_steps/symlinks.py +4 -0
  173. package/scripts/instruction_core.py +4 -0
  174. package/scripts/mcp_editors.py +4 -0
  175. package/scripts/mcp_manager.py +4 -0
  176. package/scripts/mcp_sources.py +4 -0
  177. package/scripts/merge-hooks.py +4 -0
  178. package/scripts/migrate.py +4 -0
  179. package/scripts/output_filter_retirement.py +4 -0
  180. package/scripts/pack_codebase.py +4 -0
  181. package/scripts/paths.py +4 -0
  182. package/scripts/plugin.py +4 -0
  183. package/scripts/plugin_schema.py +4 -0
  184. package/scripts/projects_cli.py +4 -0
  185. package/scripts/propagate_global.py +4 -0
  186. package/scripts/remove_rule.py +4 -0
  187. package/scripts/rule_sources.py +4 -0
  188. package/scripts/secure_fs.py +4 -0
  189. package/scripts/session_state.py +4 -0
  190. package/scripts/session_token_stats.py +4 -0
  191. package/scripts/skill_pointer.py +4 -0
  192. package/scripts/stats.py +4 -0
  193. package/scripts/sync.py +4 -0
  194. package/scripts/test_cohesion.py +4 -0
  195. package/scripts/uninstall.py +4 -0
  196. package/scripts/update_projects.py +4 -0
  197. package/scripts/url_fetch.py +4 -0
  198. package/scripts/validate.py +37 -1
  199. package/scripts/version_check.py +4 -0
  200. package/app/plugins/csharp-pack/README.md +0 -11
  201. package/app/plugins/csharp-pack/plugin.json +0 -18
  202. package/app/plugins/frontend-pack/README.md +0 -14
  203. package/app/plugins/frontend-pack/plugin.json +0 -22
  204. package/app/plugins/java-pack/README.md +0 -11
  205. package/app/plugins/java-pack/plugin.json +0 -18
  206. package/app/plugins/kotlin-pack/README.md +0 -11
  207. package/app/plugins/kotlin-pack/plugin.json +0 -18
  208. package/app/plugins/research-pack/README.md +0 -14
  209. package/app/plugins/research-pack/plugin.json +0 -22
  210. package/app/plugins/ruby-pack/README.md +0 -11
  211. package/app/plugins/ruby-pack/plugin.json +0 -18
  212. package/app/plugins/rust-pack/README.md +0 -11
  213. package/app/plugins/rust-pack/plugin.json +0 -18
  214. package/app/plugins/security-pack/README.md +0 -15
  215. package/app/plugins/security-pack/plugin.json +0 -23
  216. package/app/plugins/swift-pack/README.md +0 -11
  217. package/app/plugins/swift-pack/plugin.json +0 -18
@@ -3,10 +3,10 @@ title: "SOP: Release Preparation"
3
3
  category: procedures
4
4
  service: ai-toolkit
5
5
  tags: [sop, release, version, publish, changelog, semver, provenance, sarif, ecosystem, shellcheck]
6
- version: "1.11.2"
6
+ version: "1.13.0"
7
7
  created: "2026-04-10"
8
8
  last_updated: "2026-07-27"
9
- 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)."
9
+ 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)."
10
10
  ---
11
11
 
12
12
  # SOP: Release Preparation
@@ -65,10 +65,20 @@ python3 scripts/audit_skills.py --permissions # review Bash/Write/Edit footpri
65
65
  # 5b. Ecosystem gate — snapshot must be current before tag
66
66
  python3 scripts/ecosystem_doctor.py --offline --check || { echo "STALE ecosystem snapshot — re-run doctor"; exit 1; }
67
67
 
68
+ # 5c. Licensing gate — SPDX headers, LICENSE, NOTICE, manifest consistency
69
+ npx bats tests/test_licensing.bats || { echo "LICENSING GATE FAILED"; exit 1; }
70
+
68
71
  # 6. Commit + tag + push
69
72
  git add -A && git commit -m "chore: release vX.Y.Z"
70
73
  git tag vX.Y.Z
71
- git push origin main --tags
74
+
75
+ # 6a. Assert the tag before pushing it (v4.19.0 postmortem, Phase 7)
76
+ test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" || { echo "FAIL: tag not on HEAD"; exit 1; }
77
+ 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; }
78
+
79
+ # 6b. Branch first, then the single tag by full ref. Never --tags.
80
+ git push origin main
81
+ git push origin refs/tags/vX.Y.Z
72
82
  ```
73
83
 
74
84
  ---
@@ -332,6 +342,46 @@ python3 scripts/validate.py --strict && python3 scripts/audit_skills.py --ci &&
332
342
  - Missing frontmatter → add to new KB docs
333
343
  - Broken symlink → `ai-toolkit doctor --fix`
334
344
 
345
+ ### Phase 5c: Licensing Gate (v4.20.0+)
346
+
347
+ The project is Apache-2.0. Attribution only works if the artefact actually
348
+ carries it, and every part of that is mechanically checkable.
349
+
350
+ ```bash
351
+ # The whole gate, enforced in CI. Run it here so a failure is caught before tagging.
352
+ npx bats tests/test_licensing.bats
353
+ ```
354
+
355
+ The seven assertions, and why each exists:
356
+
357
+ | Check | Fails when |
358
+ |---|---|
359
+ | 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 |
360
+ | Headers name Apache-2.0 and nothing else | A file was copied in from an MIT/GPL source with its own header intact |
361
+ | **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 |
362
+ | `LICENSE` is the complete Apache 2.0 text | The file was truncated or replaced with a summary |
363
+ | `NOTICE` carries attribution, the source URL, §4(d) and the MIT-era notice | The attribution mechanism was gutted |
364
+ | `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) |
365
+ | Every manifest declaring a licence declares Apache-2.0 | `package.json`, `manifest.json`, `plugin.json` and `package-lock.json` drifted apart |
366
+
367
+ **Adding source files in this release?** The header goes *after* the shebang,
368
+ never before it. Short SPDX form:
369
+
370
+ ```
371
+ # SPDX-License-Identifier: Apache-2.0
372
+ # Copyright 2024-2026 Lukasz Krzemien (biuro@softspark.eu)
373
+ # Source: https://github.com/softspark/ai-toolkit
374
+ ```
375
+
376
+ `//` for JavaScript. Full convention and the reasoning behind the markdown
377
+ exclusion: [Licensing](../reference/licensing.md).
378
+
379
+ **Changing the licence itself?** Do not hand-type the licence text. Take it
380
+ verbatim from a published copy and cross-verify against a second independent
381
+ copy before writing `LICENSE` — a rendered or summarised licence is not the
382
+ licence. Prior releases stay under their original terms; a licence change
383
+ applies going forward and revokes nothing already granted.
384
+
335
385
  ### Phase 5a: Supply-Chain Hardening Verification (v2.8.0+)
336
386
 
337
387
  These checks enforce the security standard introduced in v2.8.0. Do NOT tag a release until all pass.
@@ -405,9 +455,34 @@ git commit -m "chore: release vX.Y.Z"
405
455
 
406
456
  ```bash
407
457
  git tag vX.Y.Z
408
- git push origin main --tags
458
+
459
+ # Assert the tag before pushing it. Both checks are one line each and both
460
+ # have caught a real broken release.
461
+ test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" \
462
+ || { echo "FAIL: tag is not on HEAD"; exit 1; }
463
+ git show --no-patch --format=%s vX.Y.Z | grep -qx "chore: release vX.Y.Z" \
464
+ || { echo "FAIL: tag is not on the chore: release commit"; exit 1; }
465
+
466
+ # Push the branch, then the single release tag by its full ref.
467
+ git push origin main
468
+ git push origin refs/tags/vX.Y.Z
409
469
  ```
410
470
 
471
+ **Why the assertions (v4.19.0 postmortem).** v4.19.0 was tagged on a commit
472
+ that contained only a KB document and still carried `package.json` version
473
+ `4.18.0`; the actual release sat in the commit above it under a recycled
474
+ `fix:` message. `publish.yml` fired, tried to publish a version already on
475
+ npm, and failed. Nothing on npm, a tag pointing at the wrong tree, and the
476
+ only way out was rewriting a pushed commit. Both assertions above catch this
477
+ in under a second. Run them.
478
+
479
+ **Never `git push --tags`.** It pushes every local tag at once, and GitHub
480
+ suppresses tag-triggered workflow runs when many tags arrive in a single push
481
+ — the workflow silently does not fire and nothing publishes. Push the single
482
+ release tag by its full ref, as above. (Sibling evidence: this is exactly how
483
+ rag-mcp's `1.0.3` image build was skipped, when a `--tags` push carried 37
484
+ tags at once.)
485
+
411
486
  This triggers `.github/workflows/publish.yml` which:
412
487
  1. Runs `validate.py --strict`
413
488
  2. Runs `npm test`
@@ -460,7 +535,10 @@ git push origin --delete vX.Y.Z
460
535
  | 13 | ShellCheck hooks | `shellcheck --severity=warning app/hooks/*.sh` | Exit 0, no output (mirrors ci.yml; publish.yml does NOT run it) |
461
536
  | 14 | Provenance flag check | `grep -- '--provenance' .github/workflows/publish.yml` | Present |
462
537
  | 15 | Checksum-pin backfill | `sources.json` entries all have `sha256` | No unpinned URL sources |
538
+ | 15a | Licensing gate | `npx bats tests/test_licensing.bats` | 7/7 — SPDX headers, LICENSE, NOTICE, npm `files`, manifest consistency |
463
539
  | 16 | Tests | `git add -A kb/` if the KB changed, then `npm test` | All pass |
464
540
  | 17 | Commit | `git commit` | Clean working tree |
465
541
  | 18 | Tag | `git tag vX.Y.Z` | Tag exists |
466
- | 19 | Push | `git push origin main --tags` | CI triggered with `id-token: write` |
542
+ | 18a | Tag is on HEAD | `test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)"` | Exit 0 |
543
+ | 18b | Tag is on the release commit | `git show --no-patch --format=%s vX.Y.Z` | Reads `chore: release vX.Y.Z` |
544
+ | 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`. |
@@ -24,6 +24,6 @@ description: "Feature comparison of ai-toolkit vs other Claude Code toolkits and
24
24
  | Session persistence | Yes | Yes | No | No |
25
25
  | Architecture notes | **Yes** | No | No | No |
26
26
  | KB/RAG integration | **Yes** | No | No | Yes |
27
- | License | MIT | MIT | MIT | MIT |
27
+ | License | **Apache-2.0** (NOTICE attribution, change notices, patent grant) | MIT | MIT | MIT |
28
28
 
29
29
  For live benchmark data, see the [ecosystem benchmark snapshot](claude-ecosystem-benchmark-snapshot.md).
@@ -137,7 +137,7 @@ Base configs can define non-overridable constraints via the `enforce` block:
137
137
  {
138
138
  "enforce": {
139
139
  "minHookProfile": "standard",
140
- "requiredPlugins": ["security-pack"],
140
+ "requiredPlugins": ["memory-pack"],
141
141
  "forbidOverride": ["constitution", "guard-destructive"],
142
142
  "requiredAgents": ["security-auditor"]
143
143
  }
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: "Licensing"
3
+ category: reference
4
+ service: ai-toolkit
5
+ tags: [licence, apache-2.0, spdx, notice, attribution, headers, mit]
6
+ version: "1.0.0"
7
+ created: "2026-07-27"
8
+ last_updated: "2026-07-27"
9
+ 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."
10
+ ---
11
+
12
+ # Licensing
13
+
14
+ ai-toolkit is licensed under the **Apache License 2.0** from v4.20.0. Releases up
15
+ to and including v4.20.0 were published under MIT and remain available under MIT.
16
+ The change applies going forward and revokes nothing already granted.
17
+
18
+ Canonical files: [`LICENSE`](../../LICENSE) (verbatim Apache-2.0 text) and
19
+ [`NOTICE`](../../NOTICE) (attribution).
20
+
21
+ ## Why Apache-2.0, given MIT already required attribution
22
+
23
+ This is the part most often got wrong. MIT already says:
24
+
25
+ > The above copyright notice and this permission notice shall be included in all
26
+ > copies or substantial portions of the Software.
27
+
28
+ So attribution was never the new thing. What Apache-2.0 adds:
29
+
30
+ | Mechanism | MIT | Apache-2.0 |
31
+ |---|---|---|
32
+ | Copyright notice must be preserved | yes | yes |
33
+ | **`NOTICE` contents must travel into redistributions** (§4d) | — | **yes** |
34
+ | **Modified files must carry a notice saying they changed** (§4b) | — | **yes** |
35
+ | Express patent grant, terminated by patent litigation (§3) | — | yes |
36
+ | No rights to the licensor's names or marks (§6) | — | yes |
37
+
38
+ **`NOTICE` is the reason for the change.** It is the only mechanism in a
39
+ permissive licence that forces a redistributor to reproduce your attribution —
40
+ project name, copyright, source URL — somewhere their users can see it. Without
41
+ it, MIT and Apache-2.0 are close to equivalent in practice.
42
+
43
+ Consequence for packaging: `NOTICE` is listed in `package.json` `files`. A NOTICE
44
+ that does not reach the consumer cannot satisfy §4(d), so that entry is a
45
+ licensing requirement, not housekeeping, and is asserted in CI.
46
+
47
+ ## What a fork owes
48
+
49
+ Fork it, modify it, ship it commercially. Three obligations:
50
+
51
+ 1. **Carry the `NOTICE`** into your distribution (§4d).
52
+ 2. **Say which files you changed** (§4b).
53
+ 3. **Do not use the "ai-toolkit" or "SoftSpark" names or marks** as if endorsed (§6).
54
+
55
+ ## Source header convention
56
+
57
+ Short SPDX form, three lines, always **after** the shebang — an interpreter
58
+ directive must stay on line 1 — and after a Python `coding:` line if present:
59
+
60
+ ```bash
61
+ #!/usr/bin/env bash
62
+ # SPDX-License-Identifier: Apache-2.0
63
+ # Copyright 2024-2026 Lukasz Krzemien (biuro@softspark.eu)
64
+ # Source: https://github.com/softspark/ai-toolkit
65
+ #
66
+ # guard-path.sh — the file's own description continues here.
67
+ ```
68
+
69
+ `//` for JavaScript. SPDX was chosen over the 13-line Apache APPENDIX boilerplate
70
+ because it is machine-readable — licence scanners, GitHub and SBOM tooling parse
71
+ it — and because 13 lines on top of every source file buries the description that a
72
+ reader of a hook actually needs.
73
+
74
+ ### Which files get a header
75
+
76
+ | Included | Count |
77
+ |---|---:|
78
+ | `scripts/**/*.py` | 109 |
79
+ | `tests/*.bats` | 77 |
80
+ | `app/hooks/*.sh` | 32 |
81
+ | `app/skills/**/*.py`, `**/*.js` | 27 |
82
+ | `app/plugins/**/*.sh`, `**/*.py` | 6 |
83
+ | `bin/*.js`, `benchmarks/**/*.py` | 2 |
84
+ | **total** | **253** |
85
+
86
+ These are a snapshot, not a contract — the CI gate checks that *every* matching
87
+ file has a header, so the count moves with the codebase and nothing needs
88
+ updating here when it does.
89
+
90
+ ### Which files deliberately do not, and why
91
+
92
+ **No markdown file carries a header.** Not `app/skills/*/SKILL.md`, not
93
+ `app/agents/*.md`, not `app/rules/`, not `kb/`. Two reasons, both concrete:
94
+
95
+ 1. **Frontmatter.** Skill and agent files open with parsed YAML. A header above
96
+ it breaks parsing; a header below it is invisible where it matters.
97
+ 2. **Token cost.** Skill and agent descriptions load into the system prompt of
98
+ every session — measured at 5,051 and 2,750 tokens respectively. A four-line
99
+ header across 108 skills and 45 agents would be a permanent per-session cost,
100
+ billed on every conversation forever, for a notice Apache only *recommends*.
101
+ `LICENSE` and `NOTICE` carry the full terms; the headers are a convenience.
102
+
103
+ This exclusion is asserted in CI, so a well-meant sweep of the header script over
104
+ `app/skills/` fails the build rather than silently taxing every session.
105
+
106
+ ## MIT-era contributions
107
+
108
+ Contributions made while the project was MIT-licensed remain the copyright of
109
+ their authors and were received under MIT terms. Three contributors other than
110
+ the maintainer appear in the history.
111
+
112
+ MIT explicitly permits sublicensing, so those contributions are redistributed
113
+ here under Apache-2.0 **with the original MIT notice preserved verbatim** in
114
+ `NOTICE`, which is what MIT requires. This is standard practice for an MIT to
115
+ Apache-2.0 move and needs no contributor sign-off. A "clean" Apache-2.0 with no
116
+ MIT remnant would need each contributor's agreement.
117
+
118
+ *This is a description of what the project does, not legal advice.*
119
+
120
+ ## Enforcement
121
+
122
+ `tests/test_licensing.bats`, seven assertions, run by `npm test` in CI:
123
+
124
+ - every shipped source file carries an SPDX header
125
+ - headers name Apache-2.0 and nothing else
126
+ - **no** markdown file carries a header
127
+ - `LICENSE` is the complete Apache 2.0 text, appendix included
128
+ - `NOTICE` carries attribution, the source URL, §4(d) and the MIT-era notice
129
+ - `LICENSE` and `NOTICE` both appear in `package.json` `files`
130
+ - every manifest declaring a licence declares Apache-2.0
131
+
132
+ It is a test rather than a checklist line on purpose. This project has two
133
+ same-day postmortems about SOPs that existed and were skipped; CI does not skip.
134
+ [Release Preparation](../procedures/release-preparation-sop.md) Phase 5c runs the
135
+ same gate before tagging so a failure surfaces before the tag, not after.
136
+
137
+ ## If the licence ever changes again
138
+
139
+ Do not hand-type the licence text and do not paste a rendered copy — a
140
+ markdown-formatted licence is not the licence. Take it verbatim from a published
141
+ source, cross-verify against a second independent copy, and only then write
142
+ `LICENSE`. That is how the Apache-2.0 text in this repository was installed.
143
+
144
+ ## Related
145
+
146
+ - [`LICENSE`](../../LICENSE), [`NOTICE`](../../NOTICE)
147
+ - [Release Preparation SOP](../procedures/release-preparation-sop.md) — Phase 5c
148
+ - [Distribution Model](distribution-model.md) — what ships and where
@@ -125,22 +125,30 @@ ai-toolkit plugin status --editor all # show installed packs with r
125
125
 
126
126
  ## Current Experimental Packs
127
127
 
128
- | Pack | Domain | Agents | Skills | Hooks | Description |
129
- |------|--------|--------|--------|-------|-------------|
130
- | `security-pack` | security | 3 | 3 | 2 | Security auditing, threat modeling, OWASP |
131
- | `research-pack` | research | 4 | 4 | 1 | Multi-source research, synthesis, fact-checking |
132
- | `frontend-pack` | frontend | 3 | 3 | 1 | React/Vue/CSS, SEO, design engineering |
133
- | `enterprise-pack` | enterprise | 3 | 3 | 3 | Executive briefings, infra architecture, status |
134
- | `memory-pack` | memory | 0 | 1 | 2 | SQLite persistent memory with FTS5 search |
135
- | `rust-pack` | rust | 0 | 1 | 0 | Rust patterns |
136
- | `java-pack` | java | 0 | 1 | 0 | Java patterns |
137
- | `csharp-pack` | csharp | 0 | 1 | 0 | C# patterns |
138
- | `kotlin-pack` | kotlin | 0 | 1 | 0 | Kotlin patterns |
139
- | `swift-pack` | swift | 0 | 1 | 0 | Swift patterns |
140
- | `ruby-pack` | ruby | 0 | 1 | 0 | Ruby patterns |
141
-
142
- Every pack here is content that ships in this repository. None fetches anything
143
- at install time.
128
+ | Pack | Domain | Owns | Installs (claude / codex) | Description |
129
+ |------|--------|------|---------------------------|-------------|
130
+ | `memory-pack` | memory | 2 hooks, 2 scripts, 1 skill | 4 / 4 files | SQLite persistent memory with FTS5 search |
131
+ | `enterprise-pack` | enterprise | 2 hooks | 2 / 2 files | Status-line and output-style overlays |
132
+
133
+ Both packs ship content in this repository. Neither fetches anything at install
134
+ time.
135
+
136
+ ### The rule the table now enforces
137
+
138
+ **A pack must install files the core install does not.** `ai-toolkit install`
139
+ links every core skill and agent, so a manifest naming only core assets resolves
140
+ to nothing: `plugin install` reports `(0 file items)` and no file appears on
141
+ disk. This is not a subtle degradation — it is a complete no-op, identical on
142
+ every profile (`minimal`, `standard`, `strict`) and on both runtimes.
143
+
144
+ Nine packs were removed in v4.20.0 for failing this: `csharp`, `java`, `kotlin`,
145
+ `ruby`, `rust`, `swift`, `frontend`, `research`, `security`. Every one declared
146
+ only skills and agents that already ship in core, and eight of them owned nothing
147
+ but a `README.md`. Full measurement:
148
+ [`no-op-plugin-packs-removed-20260727.md`](../history/completed/no-op-plugin-packs-removed-20260727.md).
149
+
150
+ Before adding a pack, prove it does something: install core into a throwaway
151
+ `HOME`, install the pack, and check that the reported file count is above zero.
144
152
 
145
153
  **A pack that downloads a binary has been tried once and retired.** `rtk-pack`
146
154
  (v4.18.0, removed in v4.19.0) fetched a checksum-pinned artifact in