@softspark/ai-toolkit 4.31.0 → 4.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/README.md +26 -19
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/claude-app/hooks/hooks.json +4 -2
- package/app/claude-app/skills/ai-toolkit-rules/SKILL.md +30 -16
- package/app/hooks/quality-gate.sh +9 -2
- package/app/hooks.json +4 -2
- package/app/rules/common/git-team.md +33 -0
- package/app/rules/common/git-workflow.md +6 -20
- package/app/rules/common/performance.md +25 -1
- package/app/rules/common/testing.md +7 -1
- package/benchmarks/ecosystem-doctor-snapshot.json +17 -15
- package/bin/ai-toolkit.js +2 -0
- package/kb/procedures/sop-maintenance.md +6 -3
- package/kb/reference/cli-reference.md +3 -2
- package/kb/reference/global-install-model.md +16 -3
- package/kb/reference/hooks-catalog.md +5 -3
- package/kb/reference/language-rules.md +28 -10
- package/kb/reference/unique-features.md +2 -1
- package/llms-full.txt +60 -22
- package/manifest.json +2 -2
- package/package.json +5 -2
- package/scripts/benchmark_ecosystem.py +0 -1
- package/scripts/check_split.py +11 -9
- package/scripts/claude_app.py +5 -7
- package/scripts/codex_skill_adapter.py +4 -12
- package/scripts/compile_slm.py +10 -26
- package/scripts/doctor.py +322 -0
- package/scripts/evaluate_skills.py +1 -1
- package/scripts/frontmatter.py +452 -29
- package/scripts/generate_augment_rules.py +4 -4
- package/scripts/generate_cursor_mdc.py +2 -3
- package/scripts/generate_language_rules_skills.py +8 -14
- package/scripts/generate_llms_txt.py +1 -15
- package/scripts/generate_opencode_agents.py +0 -1
- package/scripts/generate_opencode_skills.py +2 -20
- package/scripts/generate_windsurf_rules.py +0 -1
- package/scripts/generator_base.py +0 -1
- package/scripts/inject_hook_cli.py +15 -2
- package/scripts/inject_mcp_cli.py +1 -2
- package/scripts/install.py +32 -1
- package/scripts/install_git_hooks.py +0 -1
- package/scripts/install_steps/ai_tools.py +65 -25
- package/scripts/install_steps/markers.py +6 -6
- package/scripts/install_steps/skill_scope.py +188 -0
- package/scripts/instruction_core.py +5 -8
- package/scripts/merge-hooks.py +13 -3
- package/scripts/pack_codebase.py +1 -1
- package/scripts/surface_manifest.py +6 -7
- package/scripts/validate.py +180 -11
|
@@ -3,9 +3,9 @@ title: "Global Install Model"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [install, global, claude, codex, plugins, local-setup]
|
|
6
|
-
version: "3.
|
|
6
|
+
version: "3.5.0"
|
|
7
7
|
created: "2026-03-26"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-09-04"
|
|
9
9
|
description: "Reference description of Claude Code global install, Claude app plugin export, project-local editor setup, global Codex plugin layering, and command responsibilities in ai-toolkit."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -17,6 +17,19 @@ description: "Reference description of Claude Code global install, Claude app pl
|
|
|
17
17
|
|
|
18
18
|
That means one machine-level install provides agents, skills, hooks, constitution, and rule files to every project without committing toolkit boilerplate into each repository.
|
|
19
19
|
|
|
20
|
+
Language knowledge skills are the one part of the global install that is
|
|
21
|
+
scoped by evidence (v4.32.0). Every `<lang>-rules` / `<lang>-patterns` skill is
|
|
22
|
+
still symlinked, but `install` and `update` read the languages detected across
|
|
23
|
+
the projects registered in `projects.json` and set `skillOverrides: off` in
|
|
24
|
+
`~/.claude/settings.json` for the others, so their descriptions stop loading
|
|
25
|
+
into every session. The entries the toolkit wrote are listed in `state.json`
|
|
26
|
+
under `managed_skill_overrides`; only those are ever removed again (when a
|
|
27
|
+
newly registered project brings the language back), a user's own override is
|
|
28
|
+
left alone. With no registered project on disk nothing is disabled.
|
|
29
|
+
`--language-skills all` restores everything and persists the choice
|
|
30
|
+
(`language_skill_scope` in `state.json`); `ai-toolkit doctor` reports the
|
|
31
|
+
resulting listing size and zero-use skills.
|
|
32
|
+
|
|
20
33
|
Other editor targets are opt-in and only use documented file surfaces. Cursor
|
|
21
34
|
rules stay project-local because Cursor's global user rules are managed through
|
|
22
35
|
the settings UI, not a stable merge-safe file. Codex supports both project and
|
|
@@ -59,7 +72,7 @@ The `--profile` flag controls how much of each editor's native surface is activa
|
|
|
59
72
|
|---------|-----------|----------|
|
|
60
73
|
| `minimal` | Smallest editor surface. Copilot still receives its root instructions, native agents, and self-contained skills; Codex still receives instructions, agents, skills, and native safety hooks. | You want the smallest supported footprint. |
|
|
61
74
|
| `standard` (default) | Claude Code + editor rule files. Includes Gemini and Antigravity hooks plus native Copilot instructions, agents, portable skills, and hooks. | Day-to-day installs. Most users. |
|
|
62
|
-
| `strict` | Everything in `standard` plus git-hook wiring for commit-time safety checks
|
|
75
|
+
| `strict` | Everything in `standard` plus git-hook wiring for commit-time safety checks and the `git-team` common rule (feature branches, PR size, required approval, review SLA). | Tight team with zero tolerance for drift. A solo maintainer releasing straight to `main` wants `standard`, which keeps the solo-safe `git-workflow` core only. |
|
|
63
76
|
| `full` | Every native surface across every editor: hooks, sub-agents, custom commands, skill pointers for Cursor / Windsurf / Gemini / Augment / Antigravity. | You want maximum coverage and understand that each editor will carry generated files under its own layout. |
|
|
64
77
|
|
|
65
78
|
Codex installs materialize the full skill catalog under `.agents/skills/`
|
|
@@ -3,9 +3,9 @@ title: "Hooks Catalog"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.12.0"
|
|
7
7
|
created: "2026-03-27"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-09-04"
|
|
9
9
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -190,6 +190,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
190
190
|
| Matcher | *(all)* |
|
|
191
191
|
| Script | `~/.softspark/ai-toolkit/hooks/quality-check.sh` |
|
|
192
192
|
| Fires | After every Claude response |
|
|
193
|
+
| Mode | Background (`"async": true`). The linter (`npx tsc`, `ruff`) was the bulk of a 3.3 s median Stop chain; its output is advisory and reaches you when it finishes instead of holding the turn open |
|
|
193
194
|
|
|
194
195
|
**Action:** Runs language-appropriate linter:
|
|
195
196
|
- Python: `ruff check .`
|
|
@@ -208,6 +209,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
208
209
|
| Matcher | *(all)* |
|
|
209
210
|
| Script | `~/.softspark/ai-toolkit/hooks/save-session.sh` |
|
|
210
211
|
| Fires | After every Claude response |
|
|
212
|
+
| Mode | Background (`"async": true`): writes a file and exits 0, nothing to wait for |
|
|
211
213
|
|
|
212
214
|
**Action:** Writes enriched session context to the per-repo session store (`~/.softspark/ai-toolkit/sessions/<repo-key>/session-context.md`) for cross-session persistence. Captures:
|
|
213
215
|
- Session ID and last assistant message (first 5 lines)
|
|
@@ -225,7 +227,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
225
227
|
| Script | `~/.softspark/ai-toolkit/hooks/quality-gate.sh` |
|
|
226
228
|
| Fires | Before Claude is allowed to finish a response |
|
|
227
229
|
|
|
228
|
-
**Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session.
|
|
230
|
+
**Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session. Ruff runs only when the project configured it (`ruff.toml`, `.ruff.toml`, or a `[tool.ruff]` table in `pyproject.toml`); a `pyproject.toml` that only carries build or pytest/mypy metadata does not trigger `ruff check .` under whatever configuration the machine resolves (v4.32.0).
|
|
229
231
|
|
|
230
232
|
Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
231
233
|
|
|
@@ -3,9 +3,9 @@ title: "Language Rules System"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [rules, languages, coding-style, testing, patterns, security]
|
|
6
|
-
version: "2.
|
|
6
|
+
version: "2.2.0"
|
|
7
7
|
created: "2026-04-07"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-09-04"
|
|
9
9
|
description: "Reference for the language-specific rules system: 13 per-language rule sets shipped as knowledge skills, plus common rules installed as Claude Code path-scoped project rules."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -55,7 +55,7 @@ app/rules/
|
|
|
55
55
|
└── medplum/
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
**Total: 13 per-language directories × 5 files + 1 common directory ×
|
|
58
|
+
**Total: 13 per-language directories × 5 files + 1 common directory × 6 files (5 in every profile + `git-team` in `strict`) + 3 standalone files** (see README.md for canonical count). Per-language directories ship as `<lang>-rules` knowledge skills; the common directory is installed as Claude Code `.claude/rules/ai-toolkit-*.md` files.
|
|
59
59
|
|
|
60
60
|
## Supported Languages
|
|
61
61
|
|
|
@@ -145,13 +145,16 @@ Common rules are installed as path-scoped Claude Code rule files:
|
|
|
145
145
|
```
|
|
146
146
|
.claude/rules/
|
|
147
147
|
├── ai-toolkit-coding-style.md
|
|
148
|
+
├── ai-toolkit-git-team.md # --profile strict only
|
|
148
149
|
├── ai-toolkit-git-workflow.md
|
|
149
150
|
├── ai-toolkit-performance.md
|
|
150
151
|
├── ai-toolkit-security.md
|
|
151
152
|
└── ai-toolkit-testing.md
|
|
152
153
|
```
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
A source rule may also carry `profiles:` (same block-list form). `git-team` declares `profiles: ["strict"]`: branching, pull-request, and review conventions for teams, kept out of `standard` so a solo maintainer who releases straight to `main` is not told to open PRs against themselves. Rerunning `install --local` with a different profile adds or removes the managed file. Only the Claude Code local install honours `profiles`; the Claude app export, `compile-slm`, and editor `lang-common` bundles still receive every common rule (see `DECISIONS.md`, 2026-09-04).
|
|
156
|
+
|
|
157
|
+
Each file's `paths` frontmatter is copied from the source rule in `app/rules/common/<category>.md`. A source rule without a `paths` block is always-on:
|
|
155
158
|
|
|
156
159
|
```yaml
|
|
157
160
|
---
|
|
@@ -160,6 +163,18 @@ paths:
|
|
|
160
163
|
---
|
|
161
164
|
```
|
|
162
165
|
|
|
166
|
+
A source rule with a `paths` block is path-scoped, so Claude Code loads it only when a matching file is touched. As of v4.32.0 `testing` (`**/*.test.*`, `**/*.spec.*`, `**/test_*`, `**/*_test.*`, `**/tests/**`) and `performance` (source-file extensions plus `**/*.sql`) are scoped; `coding-style`, `git-workflow`, and `security` stay always-on because they carry prohibitions that must hold in every session. To change a scope, edit the source frontmatter; `validate.py` rejects inline lists and unquoted globs because the installer reads only the block form:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
---
|
|
170
|
+
language: common
|
|
171
|
+
category: testing
|
|
172
|
+
version: "1.1.0"
|
|
173
|
+
paths:
|
|
174
|
+
- "**/tests/**"
|
|
175
|
+
---
|
|
176
|
+
```
|
|
177
|
+
|
|
163
178
|
The project `CLAUDE.md` receives only a compact index between a single named marker (the per-language markers from v1.x are no longer used):
|
|
164
179
|
|
|
165
180
|
```
|
|
@@ -167,10 +182,13 @@ The project `CLAUDE.md` receives only a compact index between a single named mar
|
|
|
167
182
|
# Language Rules
|
|
168
183
|
|
|
169
184
|
Common ai-toolkit rules live in `.claude/rules/ai-toolkit-*.md`
|
|
170
|
-
with Claude Code `paths` frontmatter
|
|
171
|
-
|
|
185
|
+
with Claude Code `paths` frontmatter instead of expanding this
|
|
186
|
+
CLAUDE.md. Always-on rules load in every session; path-scoped rules
|
|
187
|
+
load only when a matching file is touched.
|
|
188
|
+
|
|
189
|
+
Always-on: `.claude/rules/ai-toolkit-coding-style.md`, ...
|
|
172
190
|
|
|
173
|
-
|
|
191
|
+
Path-scoped: `.claude/rules/ai-toolkit-performance.md`, ...
|
|
174
192
|
|
|
175
193
|
Language-specific rules live in `<lang>-rules` knowledge skills (e.g.
|
|
176
194
|
`python-rules`, `typescript-rules`) and load automatically when their
|
|
@@ -207,7 +225,7 @@ Language rules are tracked as modules in `manifest.json`:
|
|
|
207
225
|
|
|
208
226
|
| Module | Description |
|
|
209
227
|
|--------|-------------|
|
|
210
|
-
| `rules-common` | Common coding rules (5
|
|
228
|
+
| `rules-common` | Common coding rules (6 files: 5 in every profile, `git-team` in `strict` only), included in `standard` profile |
|
|
211
229
|
| `rules-typescript` | TypeScript-specific rules |
|
|
212
230
|
| `rules-python` | Python-specific rules |
|
|
213
231
|
| `rules-golang` | Go-specific rules |
|
|
@@ -228,9 +246,9 @@ Language rules are tracked as modules in `manifest.json`:
|
|
|
228
246
|
|---|---|---|---|
|
|
229
247
|
| Source | `app/rules/common/` | `app/rules/<lang>/` | `app/skills/<name>/SKILL.md` |
|
|
230
248
|
| Delivery to Claude | Path-scoped `.claude/rules/ai-toolkit-*.md` files (`--local`) + compact `CLAUDE.md` index | Generated as `<lang>-rules` knowledge skills, loaded contextually | Loaded contextually by description match |
|
|
231
|
-
| Visibility |
|
|
249
|
+
| Visibility | Always-on (`coding-style`, `git-workflow`, `security`) or loaded when a matching file is touched (`testing`, `performance`) | Loaded when triggers match (file extensions, framework names) | Loaded when triggers match |
|
|
232
250
|
| Scope | Language-agnostic standards (security, git, testing, perf, style) | Per-language coding-style, frameworks, patterns, security, testing | Domain skills (testing, debugging, RAG, etc.) |
|
|
233
|
-
| Install | `ai-toolkit install --local` | Global install (skills directory is symlinked) | Global install |
|
|
251
|
+
| Install | `ai-toolkit install --local` | Global install (skills directory is symlinked); skills for languages no registered project uses are turned off via `skillOverrides` (`--language-skills detected`, the default) unless `--language-skills all` was chosen | Global install |
|
|
234
252
|
| Other editors | Inlined into editor-specific rule files | Inlined into editor-specific rule files (still full content, not skills) | N/A |
|
|
235
253
|
|
|
236
254
|
Per-language content delivered as a knowledge skill is the same Markdown that other editors receive inlined. The split exists only for Claude, where the Agent Skills progressive-disclosure mechanism keeps the system prompt small.
|
|
@@ -4,7 +4,7 @@ category: reference
|
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [features, differentiators, constitution, hooks, security, tdd, memory]
|
|
6
6
|
created: "2026-04-13"
|
|
7
|
-
last_updated: "2026-
|
|
7
|
+
last_updated: "2026-09-04"
|
|
8
8
|
description: "Detailed description of ai-toolkit's unique features: constitution enforcement, hooks system, security scanning, effort budgeting, quality gates, and more."
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -119,6 +119,7 @@ added after the thing it checks had already shipped broken.
|
|
|
119
119
|
| **Public surface** (`surface_manifest.py` + `app/surface.json`) | a skill, agent, CLI command, frontmatter field, hook, KB category or pack disappearing | `BACKWARD_COMPATIBILITY.md` listed the surfaces; renaming one still left every check green |
|
|
120
120
|
| **Script invocation** (`validate.py`) | a skill running its own script by any path other than `${CLAUDE_SKILL_DIR}`, or through the wrong interpreter | nine skills shipped invocations that resolved only in the repo, never on an installed machine |
|
|
121
121
|
| **Skill body budget** (`validate.py`) | a `SKILL.md` body over 20,000 bytes; warns over 18,000 | the body loads on every trigger match, including accidental ones; three skills sat at 24–35 KB |
|
|
122
|
+
| **Skill description budget** (`validate.py`) | a description over 1,024 characters (the Agent Skills cap; the runtime truncates past it), or an unquoted description containing `: ` or ` #` (strict YAML drops every field, `allowed-tools` included); warns over 400; applied to plugin-pack skills too | two installed skills sat at 791 and 883 characters and made up 8% of the model's skill listing on their own |
|
|
122
123
|
| **Split integrity** (`check_split.py`) | a body → `reference/` refactor that lost a fenced code line, a required section, the description, or a working link | run by hand during a split; caught a heading corrupted inside a fenced example on first use |
|
|
123
124
|
|
|
124
125
|
The surface check is deliberately one-directional: **removals fail, additions pass.**
|
package/llms-full.txt
CHANGED
|
@@ -7204,9 +7204,9 @@ title: "SOP: AI Toolkit Maintenance"
|
|
|
7204
7204
|
category: procedures
|
|
7205
7205
|
service: ai-toolkit
|
|
7206
7206
|
tags: [sop, maintenance, agents, skills, install]
|
|
7207
|
-
version: "3.
|
|
7207
|
+
version: "3.5.0"
|
|
7208
7208
|
created: "2026-03-23"
|
|
7209
|
-
last_updated: "2026-
|
|
7209
|
+
last_updated: "2026-09-04"
|
|
7210
7210
|
description: "Standard operating procedures for installing, maintaining, and evolving the ai-toolkit."
|
|
7211
7211
|
---
|
|
7212
7212
|
|
|
@@ -7430,7 +7430,9 @@ that runtime should receive the change.
|
|
|
7430
7430
|
greets the user with a traceback, and one that reads stdin must answer an
|
|
7431
7431
|
empty stdin with an error rather than blocking forever.
|
|
7432
7432
|
3. Update `kb/reference/skills-catalog.md` and `app/ARCHITECTURE.md`
|
|
7433
|
-
4. Run `scripts/validate.py` — it checks the invocation, the body budget,
|
|
7433
|
+
4. Run `scripts/validate.py` — it checks the invocation, the body budget, the
|
|
7434
|
+
description budget (warn over 400 characters, error over 1024; unquoted
|
|
7435
|
+
descriptions containing `: ` or ` #` are rejected, use `>-`), and
|
|
7434
7436
|
`reference/` link resolution
|
|
7435
7437
|
5. Run `python3 scripts/surface_manifest.py` before the next release to adopt the
|
|
7436
7438
|
new skill into the protected surface
|
|
@@ -7506,6 +7508,7 @@ bats tests/test_install.bats tests/test_codex.bats
|
|
|
7506
7508
|
bats tests/test_claude_app.bats tests/test_hooks_per_editor.bats
|
|
7507
7509
|
python3 scripts/claude_app.py verify
|
|
7508
7510
|
python3 scripts/validate.py --strict
|
|
7511
|
+
npm run test:py # pytest over scripts/ logic incl. the frontmatter corpus test (dev venv, see CONTRIBUTING.md)
|
|
7509
7512
|
```
|
|
7510
7513
|
|
|
7511
7514
|
## Managing Plugins
|
|
@@ -10453,7 +10456,7 @@ category: reference
|
|
|
10453
10456
|
service: ai-toolkit
|
|
10454
10457
|
tags: [cli, commands, reference, install, update, plugin, mcp, telemetry]
|
|
10455
10458
|
created: "2026-04-13"
|
|
10456
|
-
last_updated: "2026-
|
|
10459
|
+
last_updated: "2026-09-04"
|
|
10457
10460
|
description: "Complete CLI reference for all ai-toolkit commands, options, and flags."
|
|
10458
10461
|
---
|
|
10459
10462
|
|
|
@@ -10468,6 +10471,7 @@ Usage: ai-toolkit <command> [options]
|
|
|
10468
10471
|
| Command | Description |
|
|
10469
10472
|
|---------|-------------|
|
|
10470
10473
|
| `install` | First-time global install into `~/.claude/` + Cursor, Windsurf, Gemini |
|
|
10474
|
+
| `install --language-skills detected\|all` | `detected` (default): turn off `<lang>-rules`/`<lang>-patterns` skills for languages no registered project uses, via `skillOverrides` in `~/.claude/settings.json` (entries are tracked in `state.json` and restored when a project brings the language back; a user's own override is never touched); `all`: keep every language skill on. The choice persists across `install`/`update` |
|
|
10471
10475
|
| `install --local` | Claude Code configs only; add `--editors all` or `--editors cursor,aider` for other tools |
|
|
10472
10476
|
| `update` | Re-apply toolkit after `npm install -g @softspark/ai-toolkit@latest` |
|
|
10473
10477
|
| `update --local` | Re-apply + auto-detect editors from existing project files |
|
|
@@ -10475,7 +10479,7 @@ Usage: ai-toolkit <command> [options]
|
|
|
10475
10479
|
| `status` | Show installed modules and version |
|
|
10476
10480
|
| `uninstall` | Remove toolkit from `~/.claude/` |
|
|
10477
10481
|
| `validate` | Verify toolkit integrity (`--strict` for CI-grade, warnings = errors) |
|
|
10478
|
-
| `doctor` | Diagnose install health, hooks, quick-win assets,
|
|
10482
|
+
| `doctor` | Diagnose install health, hooks, quick-win assets, artifact drift, context budget (est. resident tokens of the skill/agent listings and user rules, plus skills with zero recorded use; read-only, prints the `skillOverrides` key to paste), and permission rules (`permissions.allow` wildcards on interpreters, task runners, package installs, `gh api`, `curl`, `git fetch`, destructive commands; warns only, never edits) |
|
|
10479
10483
|
| `doctor --fix` | Auto-repair broken symlinks, missing hooks, stale artifacts |
|
|
10480
10484
|
| `eject [dir]` | Export standalone config (no symlinks, no toolkit dependency) |
|
|
10481
10485
|
| `claude-app export [--output FILE] [--no-custom-rules] [--verify]` | Build an uploadable Claude Chat/Desktop/Cowork plugin ZIP and global-instructions file |
|
|
@@ -12780,9 +12784,9 @@ title: "Global Install Model"
|
|
|
12780
12784
|
category: reference
|
|
12781
12785
|
service: ai-toolkit
|
|
12782
12786
|
tags: [install, global, claude, codex, plugins, local-setup]
|
|
12783
|
-
version: "3.
|
|
12787
|
+
version: "3.5.0"
|
|
12784
12788
|
created: "2026-03-26"
|
|
12785
|
-
last_updated: "2026-
|
|
12789
|
+
last_updated: "2026-09-04"
|
|
12786
12790
|
description: "Reference description of Claude Code global install, Claude app plugin export, project-local editor setup, global Codex plugin layering, and command responsibilities in ai-toolkit."
|
|
12787
12791
|
---
|
|
12788
12792
|
|
|
@@ -12794,6 +12798,19 @@ description: "Reference description of Claude Code global install, Claude app pl
|
|
|
12794
12798
|
|
|
12795
12799
|
That means one machine-level install provides agents, skills, hooks, constitution, and rule files to every project without committing toolkit boilerplate into each repository.
|
|
12796
12800
|
|
|
12801
|
+
Language knowledge skills are the one part of the global install that is
|
|
12802
|
+
scoped by evidence (v4.32.0). Every `<lang>-rules` / `<lang>-patterns` skill is
|
|
12803
|
+
still symlinked, but `install` and `update` read the languages detected across
|
|
12804
|
+
the projects registered in `projects.json` and set `skillOverrides: off` in
|
|
12805
|
+
`~/.claude/settings.json` for the others, so their descriptions stop loading
|
|
12806
|
+
into every session. The entries the toolkit wrote are listed in `state.json`
|
|
12807
|
+
under `managed_skill_overrides`; only those are ever removed again (when a
|
|
12808
|
+
newly registered project brings the language back), a user's own override is
|
|
12809
|
+
left alone. With no registered project on disk nothing is disabled.
|
|
12810
|
+
`--language-skills all` restores everything and persists the choice
|
|
12811
|
+
(`language_skill_scope` in `state.json`); `ai-toolkit doctor` reports the
|
|
12812
|
+
resulting listing size and zero-use skills.
|
|
12813
|
+
|
|
12797
12814
|
Other editor targets are opt-in and only use documented file surfaces. Cursor
|
|
12798
12815
|
rules stay project-local because Cursor's global user rules are managed through
|
|
12799
12816
|
the settings UI, not a stable merge-safe file. Codex supports both project and
|
|
@@ -12836,7 +12853,7 @@ The `--profile` flag controls how much of each editor's native surface is activa
|
|
|
12836
12853
|
|---------|-----------|----------|
|
|
12837
12854
|
| `minimal` | Smallest editor surface. Copilot still receives its root instructions, native agents, and self-contained skills; Codex still receives instructions, agents, skills, and native safety hooks. | You want the smallest supported footprint. |
|
|
12838
12855
|
| `standard` (default) | Claude Code + editor rule files. Includes Gemini and Antigravity hooks plus native Copilot instructions, agents, portable skills, and hooks. | Day-to-day installs. Most users. |
|
|
12839
|
-
| `strict` | Everything in `standard` plus git-hook wiring for commit-time safety checks
|
|
12856
|
+
| `strict` | Everything in `standard` plus git-hook wiring for commit-time safety checks and the `git-team` common rule (feature branches, PR size, required approval, review SLA). | Tight team with zero tolerance for drift. A solo maintainer releasing straight to `main` wants `standard`, which keeps the solo-safe `git-workflow` core only. |
|
|
12840
12857
|
| `full` | Every native surface across every editor: hooks, sub-agents, custom commands, skill pointers for Cursor / Windsurf / Gemini / Augment / Antigravity. | You want maximum coverage and understand that each editor will carry generated files under its own layout. |
|
|
12841
12858
|
|
|
12842
12859
|
Codex installs materialize the full skill catalog under `.agents/skills/`
|
|
@@ -13225,9 +13242,9 @@ title: "Hooks Catalog"
|
|
|
13225
13242
|
category: reference
|
|
13226
13243
|
service: ai-toolkit
|
|
13227
13244
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
13228
|
-
version: "1.
|
|
13245
|
+
version: "1.12.0"
|
|
13229
13246
|
created: "2026-03-27"
|
|
13230
|
-
last_updated: "2026-
|
|
13247
|
+
last_updated: "2026-09-04"
|
|
13231
13248
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
13232
13249
|
---
|
|
13233
13250
|
|
|
@@ -13412,6 +13429,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
13412
13429
|
| Matcher | *(all)* |
|
|
13413
13430
|
| Script | `~/.softspark/ai-toolkit/hooks/quality-check.sh` |
|
|
13414
13431
|
| Fires | After every Claude response |
|
|
13432
|
+
| Mode | Background (`"async": true`). The linter (`npx tsc`, `ruff`) was the bulk of a 3.3 s median Stop chain; its output is advisory and reaches you when it finishes instead of holding the turn open |
|
|
13415
13433
|
|
|
13416
13434
|
**Action:** Runs language-appropriate linter:
|
|
13417
13435
|
- Python: `ruff check .`
|
|
@@ -13430,6 +13448,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
13430
13448
|
| Matcher | *(all)* |
|
|
13431
13449
|
| Script | `~/.softspark/ai-toolkit/hooks/save-session.sh` |
|
|
13432
13450
|
| Fires | After every Claude response |
|
|
13451
|
+
| Mode | Background (`"async": true`): writes a file and exits 0, nothing to wait for |
|
|
13433
13452
|
|
|
13434
13453
|
**Action:** Writes enriched session context to the per-repo session store (`~/.softspark/ai-toolkit/sessions/<repo-key>/session-context.md`) for cross-session persistence. Captures:
|
|
13435
13454
|
- Session ID and last assistant message (first 5 lines)
|
|
@@ -13447,7 +13466,7 @@ Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
|
13447
13466
|
| Script | `~/.softspark/ai-toolkit/hooks/quality-gate.sh` |
|
|
13448
13467
|
| Fires | Before Claude is allowed to finish a response |
|
|
13449
13468
|
|
|
13450
|
-
**Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session.
|
|
13469
|
+
**Action:** Runs lint/typecheck. **Blocks stopping (exit 2)** if errors found, so Claude must continue and fix the issues. Missing local tooling is reported as skipped rather than blocking the session. Ruff runs only when the project configured it (`ruff.toml`, `.ruff.toml`, or a `[tool.ruff]` table in `pyproject.toml`); a `pyproject.toml` that only carries build or pytest/mypy metadata does not trigger `ruff check .` under whatever configuration the machine resolves (v4.32.0).
|
|
13451
13470
|
|
|
13452
13471
|
Skipped when `TOOLKIT_HOOK_PROFILE=minimal`.
|
|
13453
13472
|
|
|
@@ -14045,9 +14064,9 @@ title: "Language Rules System"
|
|
|
14045
14064
|
category: reference
|
|
14046
14065
|
service: ai-toolkit
|
|
14047
14066
|
tags: [rules, languages, coding-style, testing, patterns, security]
|
|
14048
|
-
version: "2.
|
|
14067
|
+
version: "2.2.0"
|
|
14049
14068
|
created: "2026-04-07"
|
|
14050
|
-
last_updated: "2026-
|
|
14069
|
+
last_updated: "2026-09-04"
|
|
14051
14070
|
description: "Reference for the language-specific rules system: 13 per-language rule sets shipped as knowledge skills, plus common rules installed as Claude Code path-scoped project rules."
|
|
14052
14071
|
---
|
|
14053
14072
|
|
|
@@ -14097,7 +14116,7 @@ app/rules/
|
|
|
14097
14116
|
└── medplum/
|
|
14098
14117
|
```
|
|
14099
14118
|
|
|
14100
|
-
**Total: 13 per-language directories × 5 files + 1 common directory ×
|
|
14119
|
+
**Total: 13 per-language directories × 5 files + 1 common directory × 6 files (5 in every profile + `git-team` in `strict`) + 3 standalone files** (see README.md for canonical count). Per-language directories ship as `<lang>-rules` knowledge skills; the common directory is installed as Claude Code `.claude/rules/ai-toolkit-*.md` files.
|
|
14101
14120
|
|
|
14102
14121
|
## Supported Languages
|
|
14103
14122
|
|
|
@@ -14187,13 +14206,16 @@ Common rules are installed as path-scoped Claude Code rule files:
|
|
|
14187
14206
|
```
|
|
14188
14207
|
.claude/rules/
|
|
14189
14208
|
├── ai-toolkit-coding-style.md
|
|
14209
|
+
├── ai-toolkit-git-team.md # --profile strict only
|
|
14190
14210
|
├── ai-toolkit-git-workflow.md
|
|
14191
14211
|
├── ai-toolkit-performance.md
|
|
14192
14212
|
├── ai-toolkit-security.md
|
|
14193
14213
|
└── ai-toolkit-testing.md
|
|
14194
14214
|
```
|
|
14195
14215
|
|
|
14196
|
-
|
|
14216
|
+
A source rule may also carry `profiles:` (same block-list form). `git-team` declares `profiles: ["strict"]`: branching, pull-request, and review conventions for teams, kept out of `standard` so a solo maintainer who releases straight to `main` is not told to open PRs against themselves. Rerunning `install --local` with a different profile adds or removes the managed file. Only the Claude Code local install honours `profiles`; the Claude app export, `compile-slm`, and editor `lang-common` bundles still receive every common rule (see `DECISIONS.md`, 2026-09-04).
|
|
14217
|
+
|
|
14218
|
+
Each file's `paths` frontmatter is copied from the source rule in `app/rules/common/<category>.md`. A source rule without a `paths` block is always-on:
|
|
14197
14219
|
|
|
14198
14220
|
```yaml
|
|
14199
14221
|
---
|
|
@@ -14202,6 +14224,18 @@ paths:
|
|
|
14202
14224
|
---
|
|
14203
14225
|
```
|
|
14204
14226
|
|
|
14227
|
+
A source rule with a `paths` block is path-scoped, so Claude Code loads it only when a matching file is touched. As of v4.32.0 `testing` (`**/*.test.*`, `**/*.spec.*`, `**/test_*`, `**/*_test.*`, `**/tests/**`) and `performance` (source-file extensions plus `**/*.sql`) are scoped; `coding-style`, `git-workflow`, and `security` stay always-on because they carry prohibitions that must hold in every session. To change a scope, edit the source frontmatter; `validate.py` rejects inline lists and unquoted globs because the installer reads only the block form:
|
|
14228
|
+
|
|
14229
|
+
```yaml
|
|
14230
|
+
---
|
|
14231
|
+
language: common
|
|
14232
|
+
category: testing
|
|
14233
|
+
version: "1.1.0"
|
|
14234
|
+
paths:
|
|
14235
|
+
- "**/tests/**"
|
|
14236
|
+
---
|
|
14237
|
+
```
|
|
14238
|
+
|
|
14205
14239
|
The project `CLAUDE.md` receives only a compact index between a single named marker (the per-language markers from v1.x are no longer used):
|
|
14206
14240
|
|
|
14207
14241
|
```
|
|
@@ -14209,10 +14243,13 @@ The project `CLAUDE.md` receives only a compact index between a single named mar
|
|
|
14209
14243
|
# Language Rules
|
|
14210
14244
|
|
|
14211
14245
|
Common ai-toolkit rules live in `.claude/rules/ai-toolkit-*.md`
|
|
14212
|
-
with Claude Code `paths` frontmatter
|
|
14213
|
-
|
|
14246
|
+
with Claude Code `paths` frontmatter instead of expanding this
|
|
14247
|
+
CLAUDE.md. Always-on rules load in every session; path-scoped rules
|
|
14248
|
+
load only when a matching file is touched.
|
|
14214
14249
|
|
|
14215
|
-
|
|
14250
|
+
Always-on: `.claude/rules/ai-toolkit-coding-style.md`, ...
|
|
14251
|
+
|
|
14252
|
+
Path-scoped: `.claude/rules/ai-toolkit-performance.md`, ...
|
|
14216
14253
|
|
|
14217
14254
|
Language-specific rules live in `<lang>-rules` knowledge skills (e.g.
|
|
14218
14255
|
`python-rules`, `typescript-rules`) and load automatically when their
|
|
@@ -14249,7 +14286,7 @@ Language rules are tracked as modules in `manifest.json`:
|
|
|
14249
14286
|
|
|
14250
14287
|
| Module | Description |
|
|
14251
14288
|
|--------|-------------|
|
|
14252
|
-
| `rules-common` | Common coding rules (5
|
|
14289
|
+
| `rules-common` | Common coding rules (6 files: 5 in every profile, `git-team` in `strict` only), included in `standard` profile |
|
|
14253
14290
|
| `rules-typescript` | TypeScript-specific rules |
|
|
14254
14291
|
| `rules-python` | Python-specific rules |
|
|
14255
14292
|
| `rules-golang` | Go-specific rules |
|
|
@@ -14270,9 +14307,9 @@ Language rules are tracked as modules in `manifest.json`:
|
|
|
14270
14307
|
|---|---|---|---|
|
|
14271
14308
|
| Source | `app/rules/common/` | `app/rules/<lang>/` | `app/skills/<name>/SKILL.md` |
|
|
14272
14309
|
| Delivery to Claude | Path-scoped `.claude/rules/ai-toolkit-*.md` files (`--local`) + compact `CLAUDE.md` index | Generated as `<lang>-rules` knowledge skills, loaded contextually | Loaded contextually by description match |
|
|
14273
|
-
| Visibility |
|
|
14310
|
+
| Visibility | Always-on (`coding-style`, `git-workflow`, `security`) or loaded when a matching file is touched (`testing`, `performance`) | Loaded when triggers match (file extensions, framework names) | Loaded when triggers match |
|
|
14274
14311
|
| Scope | Language-agnostic standards (security, git, testing, perf, style) | Per-language coding-style, frameworks, patterns, security, testing | Domain skills (testing, debugging, RAG, etc.) |
|
|
14275
|
-
| Install | `ai-toolkit install --local` | Global install (skills directory is symlinked) | Global install |
|
|
14312
|
+
| Install | `ai-toolkit install --local` | Global install (skills directory is symlinked); skills for languages no registered project uses are turned off via `skillOverrides` (`--language-skills detected`, the default) unless `--language-skills all` was chosen | Global install |
|
|
14276
14313
|
| Other editors | Inlined into editor-specific rule files | Inlined into editor-specific rule files (still full content, not skills) | N/A |
|
|
14277
14314
|
|
|
14278
14315
|
Per-language content delivered as a knowledge skill is the same Markdown that other editors receive inlined. The split exists only for Claude, where the Agent Skills progressive-disclosure mechanism keeps the system prompt small.
|
|
@@ -17070,7 +17107,7 @@ category: reference
|
|
|
17070
17107
|
service: ai-toolkit
|
|
17071
17108
|
tags: [features, differentiators, constitution, hooks, security, tdd, memory]
|
|
17072
17109
|
created: "2026-04-13"
|
|
17073
|
-
last_updated: "2026-
|
|
17110
|
+
last_updated: "2026-09-04"
|
|
17074
17111
|
description: "Detailed description of ai-toolkit's unique features: constitution enforcement, hooks system, security scanning, effort budgeting, quality gates, and more."
|
|
17075
17112
|
---
|
|
17076
17113
|
|
|
@@ -17185,6 +17222,7 @@ added after the thing it checks had already shipped broken.
|
|
|
17185
17222
|
| **Public surface** (`surface_manifest.py` + `app/surface.json`) | a skill, agent, CLI command, frontmatter field, hook, KB category or pack disappearing | `BACKWARD_COMPATIBILITY.md` listed the surfaces; renaming one still left every check green |
|
|
17186
17223
|
| **Script invocation** (`validate.py`) | a skill running its own script by any path other than `${CLAUDE_SKILL_DIR}`, or through the wrong interpreter | nine skills shipped invocations that resolved only in the repo, never on an installed machine |
|
|
17187
17224
|
| **Skill body budget** (`validate.py`) | a `SKILL.md` body over 20,000 bytes; warns over 18,000 | the body loads on every trigger match, including accidental ones; three skills sat at 24–35 KB |
|
|
17225
|
+
| **Skill description budget** (`validate.py`) | a description over 1,024 characters (the Agent Skills cap; the runtime truncates past it), or an unquoted description containing `: ` or ` #` (strict YAML drops every field, `allowed-tools` included); warns over 400; applied to plugin-pack skills too | two installed skills sat at 791 and 883 characters and made up 8% of the model's skill listing on their own |
|
|
17188
17226
|
| **Split integrity** (`check_split.py`) | a body → `reference/` refactor that lost a fenced code line, a required section, the description, or a working link | run by hand during a split; caught a heading corrupted inside a fenced example on first use |
|
|
17189
17227
|
|
|
17190
17228
|
The surface check is deliberately one-directional: **removals fail, additions pass.**
|
package/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.32.0",
|
|
3
3
|
"components": {
|
|
4
4
|
"agents": {
|
|
5
5
|
"description": "44 specialized agents (orchestrator, backend, frontend, security, devops, etc.)",
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
"default": true
|
|
142
142
|
},
|
|
143
143
|
"rules-common": {
|
|
144
|
-
"description": "Common coding rules (
|
|
144
|
+
"description": "Common coding rules (6 files; git-team ships with the strict profile only)",
|
|
145
145
|
"default": true
|
|
146
146
|
},
|
|
147
147
|
"rules-typescript": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.32.0",
|
|
4
4
|
"description": "AI coding toolkit: 109 skills, 44 agents, 14 developer-tool integrations, recoverable native tool-output filtering, Claude Chat/Cowork export, safety constitution, SARIF audit, and signed npm provenance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -75,7 +75,10 @@
|
|
|
75
75
|
"generate:all": "npm run generate:language-rules && npm run generate:claude-app && npm run generate:agents && npm run generate:opencode-agents && npm run generate:opencode-commands && npm run generate:opencode-skills && npm run generate:cursor && npm run generate:cursor-mdc && npm run generate:windsurf && npm run generate:windsurf-rules && npm run generate:copilot && npm run generate:gemini && npm run generate:gemini-agents && npm run generate:cline && npm run generate:cline-hooks && npm run generate:roo && npm run generate:roo-rules && npm run generate:aider && npm run generate:augment-rules && npm run generate:antigravity && npm run generate:llms && npm run generate:badges",
|
|
76
76
|
"generate:badges": "python3 scripts/sync_badges.py",
|
|
77
77
|
"surface": "python3 scripts/surface_manifest.py",
|
|
78
|
-
"surface:update": "python3 scripts/surface_manifest.py --update"
|
|
78
|
+
"surface:update": "python3 scripts/surface_manifest.py --update",
|
|
79
|
+
"test:py": "python3 -m pytest tests/python",
|
|
80
|
+
"lint:py": "ruff check scripts --select E,F --ignore E501,E402 --line-length 120 --extend-exclude app/skills/*/scripts,benchmarks",
|
|
81
|
+
"typecheck:py": "python3 -m mypy"
|
|
79
82
|
},
|
|
80
83
|
"files": [
|
|
81
84
|
"bin/",
|
package/scripts/check_split.py
CHANGED
|
@@ -54,6 +54,8 @@ from pathlib import Path
|
|
|
54
54
|
|
|
55
55
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
56
56
|
from _common import toolkit_dir as default_toolkit_dir
|
|
57
|
+
from frontmatter import FrontmatterError
|
|
58
|
+
from frontmatter import split_frontmatter as _split_frontmatter
|
|
57
59
|
|
|
58
60
|
# Sections that carry prescriptive process and environment-specific traps.
|
|
59
61
|
# They must load on every run, so they never move down into reference/.
|
|
@@ -75,16 +77,16 @@ NON_FILE_PREFIXES = ("#", "/", "mailto:", "tel:", "$")
|
|
|
75
77
|
# ---------------------------------------------------------------------------
|
|
76
78
|
|
|
77
79
|
def split_frontmatter(text: str) -> tuple[str, str]:
|
|
78
|
-
"""Return (frontmatter_block, body). Frontmatter is '' when absent.
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
"""Return (frontmatter_block, body). Frontmatter is '' when absent.
|
|
81
|
+
|
|
82
|
+
An unterminated block counts as body rather than being swallowed, so the
|
|
83
|
+
split gate still compares every byte of such a file.
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
block, body = _split_frontmatter(text)
|
|
87
|
+
except FrontmatterError:
|
|
81
88
|
return "", text
|
|
82
|
-
|
|
83
|
-
if lines[idx].strip() == "---":
|
|
84
|
-
return "\n".join(lines[1:idx]), "\n".join(lines[idx + 1:])
|
|
85
|
-
# Unterminated frontmatter — treat the whole file as body rather than
|
|
86
|
-
# silently swallowing it.
|
|
87
|
-
return "", text
|
|
89
|
+
return block or "", body
|
|
88
90
|
|
|
89
91
|
|
|
90
92
|
def description_of(frontmatter: str) -> str:
|
package/scripts/claude_app.py
CHANGED
|
@@ -27,6 +27,9 @@ import tempfile
|
|
|
27
27
|
import zipfile
|
|
28
28
|
from pathlib import Path
|
|
29
29
|
|
|
30
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
31
|
+
from frontmatter import split_frontmatter # noqa: E402
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
TOOLKIT_DIR = Path(__file__).resolve().parent.parent
|
|
32
35
|
APP_DIR = TOOLKIT_DIR / "app"
|
|
@@ -55,13 +58,8 @@ def _write_text(path: Path, content: str) -> None:
|
|
|
55
58
|
|
|
56
59
|
|
|
57
60
|
def _strip_frontmatter(content: str) -> str:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return content.strip()
|
|
61
|
-
for index in range(1, len(lines)):
|
|
62
|
-
if lines[index].strip() == "---":
|
|
63
|
-
return "\n".join(lines[index + 1 :]).strip()
|
|
64
|
-
return content.strip()
|
|
61
|
+
"""Body of a rule file with surrounding whitespace removed."""
|
|
62
|
+
return split_frontmatter(content)[1].strip()
|
|
65
63
|
|
|
66
64
|
|
|
67
65
|
def render_plugin_hooks() -> str:
|
|
@@ -280,8 +280,10 @@ def _build_portable_skill_text(skill_file: Path, platform: str) -> str:
|
|
|
280
280
|
if invocation_lines:
|
|
281
281
|
rendered_frontmatter += "\n" + "\n".join(invocation_lines)
|
|
282
282
|
else:
|
|
283
|
-
frontmatter
|
|
284
|
-
|
|
283
|
+
# Native skills pass their frontmatter through untouched. The old
|
|
284
|
+
# line-by-line re-render flattened nested keys (`hooks:` blocks) into
|
|
285
|
+
# top-level `key: ` lines, which is not the document the author wrote.
|
|
286
|
+
rendered_frontmatter = match.group("frontmatter").strip("\n")
|
|
285
287
|
|
|
286
288
|
return f"---\n{rendered_frontmatter}\n---\n{body.rstrip()}\n"
|
|
287
289
|
|
|
@@ -1112,16 +1114,6 @@ def _is_relative_to(path: Path, parent: Path) -> bool:
|
|
|
1112
1114
|
return False
|
|
1113
1115
|
|
|
1114
1116
|
|
|
1115
|
-
def _parse_frontmatter(frontmatter_text: str) -> list[tuple[str, str]]:
|
|
1116
|
-
entries: list[tuple[str, str]] = []
|
|
1117
|
-
for line in frontmatter_text.splitlines():
|
|
1118
|
-
if ":" not in line:
|
|
1119
|
-
continue
|
|
1120
|
-
key, value = line.split(":", 1)
|
|
1121
|
-
entries.append((key.strip(), value.strip()))
|
|
1122
|
-
return entries
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
1117
|
def _invocation_metadata_lines(frontmatter_text: str) -> list[str]:
|
|
1126
1118
|
"""Return exact canonical invocation lines, rejecting duplicate fields."""
|
|
1127
1119
|
fields = ("user-invocable", "disable-model-invocation")
|